From c7cbdc6d197b846540e993dcc63ce4e1df78c14a Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Thu, 24 Jul 2025 13:20:19 +0200
Subject: [PATCH 01/10] Feature: Add "Digital Signatures" tab to the properties
window
---
.../Enums/PropertiesNavigationViewItemType.cs | 7 +-
.../PropertiesNavigationViewItemFactory.cs | 28 ++-
.../Data/Models/SignatureInfoItem.cs | 77 +++++++
.../Helpers/Win32/Win32PInvoke.Methods.cs | 39 +++-
src/Files.App/Strings/en-US/Resources.resw | 18 ++
.../Utils/Signatures/DigitalSignaturesUtil.cs | 15 ++
.../Properties/MainPropertiesViewModel.cs | 3 +-
.../Properties/SignaturesViewModel.cs | 28 +++
.../Views/Properties/SignaturesPage.xaml | 193 ++++++++++++++++++
.../Views/Properties/SignaturesPage.xaml.cs | 40 ++++
10 files changed, 435 insertions(+), 13 deletions(-)
create mode 100644 src/Files.App/Data/Models/SignatureInfoItem.cs
create mode 100644 src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
create mode 100644 src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
create mode 100644 src/Files.App/Views/Properties/SignaturesPage.xaml
create mode 100644 src/Files.App/Views/Properties/SignaturesPage.xaml.cs
diff --git a/src/Files.App/Data/Enums/PropertiesNavigationViewItemType.cs b/src/Files.App/Data/Enums/PropertiesNavigationViewItemType.cs
index 4b33779e6c1d..766bb13cc863 100644
--- a/src/Files.App/Data/Enums/PropertiesNavigationViewItemType.cs
+++ b/src/Files.App/Data/Enums/PropertiesNavigationViewItemType.cs
@@ -47,5 +47,10 @@ public enum PropertiesNavigationViewItemType
/// Shortcut page type
///
Shortcut,
- }
+
+ ///
+ /// Signatures page type
+ ///
+ Signatures,
+ }
}
diff --git a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
index f546301858e4..44b0c569740d 100644
--- a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
+++ b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
@@ -61,9 +61,16 @@ public static ObservableCollection Initialize
ItemType = PropertiesNavigationViewItemType.Compatibility,
ThemedIconStyle = (Style)Application.Current.Resources["App.ThemedIcons.Properties.Compatability"],
};
-
- PropertiesNavigationViewItems.Add(generalItem);
- PropertiesNavigationViewItems.Add(securityItem);
+ var signaturesItem = new NavigationViewItemButtonStyleItem()
+ {
+ Name = Strings.Signatures.GetLocalizedResource(),
+ ItemType = PropertiesNavigationViewItemType.Signatures,
+ ThemedIconStyle = (Style)Application.Current.Resources["App.ThemedIcons.Properties.Signatures"],
+ };
+
+ PropertiesNavigationViewItems.Add(generalItem);
+ PropertiesNavigationViewItems.Add(signaturesItem);
+ PropertiesNavigationViewItems.Add(securityItem);
PropertiesNavigationViewItems.Add(hashesItem);
PropertiesNavigationViewItems.Add(shortcutItem);
PropertiesNavigationViewItems.Add(libraryItem);
@@ -89,7 +96,8 @@ public static ObservableCollection Initialize
PropertiesNavigationViewItems.Remove(securityItem);
PropertiesNavigationViewItems.Remove(customizationItem);
PropertiesNavigationViewItems.Remove(hashesItem);
- }
+ PropertiesNavigationViewItems.Remove(signaturesItem);
+ }
else if (item is ListedItem listedItem)
{
var isShortcut = listedItem.IsShortcut;
@@ -106,10 +114,13 @@ public static ObservableCollection Initialize
if (!securityItemEnabled)
PropertiesNavigationViewItems.Remove(securityItem);
- if (!hashItemEnabled)
- PropertiesNavigationViewItems.Remove(hashesItem);
+ if (!hashItemEnabled)
+ {
+ PropertiesNavigationViewItems.Remove(hashesItem);
+ PropertiesNavigationViewItems.Remove(signaturesItem);
+ }
- if (!isShortcut)
+ if (!isShortcut)
PropertiesNavigationViewItems.Remove(shortcutItem);
if (!isLibrary)
@@ -132,7 +143,8 @@ public static ObservableCollection Initialize
PropertiesNavigationViewItems.Remove(detailsItem);
PropertiesNavigationViewItems.Remove(customizationItem);
PropertiesNavigationViewItems.Remove(compatibilityItem);
- }
+ PropertiesNavigationViewItems.Remove(signaturesItem);
+ }
return PropertiesNavigationViewItems;
}
diff --git a/src/Files.App/Data/Models/SignatureInfoItem.cs b/src/Files.App/Data/Models/SignatureInfoItem.cs
new file mode 100644
index 000000000000..5a3593bb93f6
--- /dev/null
+++ b/src/Files.App/Data/Models/SignatureInfoItem.cs
@@ -0,0 +1,77 @@
+// Copyright (c) Files Community
+// Licensed under the MIT License.
+
+using System.Windows.Input;
+
+namespace Files.App.Data.Models
+{
+ public sealed partial class SignatureInfoItem : ObservableObject
+ {
+ private string _Version = string.Empty;
+ public string Version
+ {
+ get => _Version;
+ set => SetProperty(ref _Version, value);
+ }
+
+ private string _IssuedBy = string.Empty;
+ public string IssuedBy
+ {
+ get => _IssuedBy;
+ set => SetProperty(ref _IssuedBy, value);
+ }
+
+ private string _IssuedTo = string.Empty;
+ public string IssuedTo
+ {
+ get => _IssuedTo;
+ set => SetProperty(ref _IssuedTo, value);
+ }
+
+ private string _ValidFromTimestamp = string.Empty;
+ public string ValidFromTimestamp
+ {
+ get => _ValidFromTimestamp;
+ set => SetProperty(ref _ValidFromTimestamp, value);
+ }
+
+ private string _ValidToTimestamp = string.Empty;
+ public string ValidToTimestamp
+ {
+ get => _ValidToTimestamp;
+ set => SetProperty(ref _ValidToTimestamp, value);
+ }
+
+ private string _VerifiedTimestamp = string.Empty;
+ public string VerifiedTimestamp
+ {
+ get => _VerifiedTimestamp;
+ set => SetProperty(ref _VerifiedTimestamp, value);
+ }
+
+ private bool _Verified = false;
+ public bool Verified
+ {
+ get => _Verified;
+ set
+ {
+ if (SetProperty(ref _Verified, value))
+ OnPropertyChanged(nameof(Glyph));
+ }
+ }
+
+ public string Glyph => Verified ? "\uE930" : "\uEA39";
+
+ public ICommand OpenDetailsCommand { get; }
+
+ public SignatureInfoItem()
+ {
+ OpenDetailsCommand = new AsyncRelayCommand(DoOpenDetails);
+ }
+
+ private Task DoOpenDetails()
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
index 5d700736a2fa..06c875be2e25 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
@@ -1,5 +1,5 @@
-// Copyright (c) 2024 Files Community
-// Licensed under the MIT License. See the LICENSE.
+// Copyright (c) Files Community
+// Licensed under the MIT License.
using System.IO;
using System.Runtime.InteropServices;
@@ -347,5 +347,38 @@ public static extern int SHGetKnownFolderPath(
IntPtr hToken,
out IntPtr pszPath
);
- }
+
+ [DllImport("wintrust.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ private static extern uint WinVerifyTrust(
+ IntPtr hwnd,
+ [MarshalAs(UnmanagedType.LPStruct)] Guid pgActionID,
+ IntPtr pWVTData
+ );
+
+ [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ private static extern bool CryptQueryObject(
+ uint dwObjectType,
+ IntPtr pvObject,
+ uint dwExpectedContentTypeFlags,
+ uint dwExpectedFormatTypeFlags,
+ uint dwFlags,
+ out uint pdwMsgAndCertEncodingType,
+ out uint pdwContentType,
+ out uint pdwFormatType,
+ out IntPtr phCertStore,
+ out IntPtr phMsg,
+ out IntPtr ppvContext
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true)]
+ private static extern bool CertCloseStore(
+ IntPtr hCertStore,
+ uint dwFlags
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true)]
+ private static extern bool CryptMsgClose(
+ IntPtr hCryptMsg
+ );
+ }
}
diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw
index fb30d3afa016..66db6101b1ef 100644
--- a/src/Files.App/Strings/en-US/Resources.resw
+++ b/src/Files.App/Strings/en-US/Resources.resw
@@ -4273,4 +4273,22 @@
Filename
+
+ Signatures
+
+
+ Signature list
+
+
+ Issued by:
+
+
+ Issued to:
+
+
+ Valid from:
+
+
+ Valid to:
+
diff --git a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
new file mode 100644
index 000000000000..97707cab1fb3
--- /dev/null
+++ b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Files Community
+// Licensed under the MIT License.
+
+namespace Files.App.Utils.Signatures
+{
+ public static class DigitalSignaturesUtil
+ {
+ public static List GetSignaturesOfItem(string filePath)
+ {
+ var signatures = new List();
+
+ return signatures;
+ }
+ }
+}
diff --git a/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs b/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
index 14a7922e0115..b3029eb9c41e 100644
--- a/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
@@ -41,7 +41,8 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
PropertiesNavigationViewItemType.Customization => typeof(CustomizationPage),
PropertiesNavigationViewItemType.Compatibility => typeof(CompatibilityPage),
PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
- _ => typeof(GeneralPage),
+ PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
+ _ => typeof(GeneralPage),
};
_mainFrame?.Navigate(page, parameter, new EntranceNavigationTransitionInfo());
diff --git a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
new file mode 100644
index 000000000000..7b83c4c0e90c
--- /dev/null
+++ b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Files Community
+// Licensed under the MIT License.
+
+using Files.App.Utils.Signatures;
+
+namespace Files.App.ViewModels.Properties
+{
+ public sealed partial class SignaturesViewModel : ObservableObject, IDisposable
+ {
+ private CancellationTokenSource _cancellationTokenSource;
+
+ public ObservableCollection Signatures { get; set; }
+
+ public SignaturesViewModel(ListedItem item)
+ {
+ _cancellationTokenSource = new();
+ Signatures = new();
+
+ var signatures = DigitalSignaturesUtil.GetSignaturesOfItem(item.ItemPath);
+ signatures.ForEach(s => Signatures.Add(s));
+ }
+
+ public void Dispose()
+ {
+ _cancellationTokenSource.Cancel();
+ }
+ }
+}
diff --git a/src/Files.App/Views/Properties/SignaturesPage.xaml b/src/Files.App/Views/Properties/SignaturesPage.xaml
new file mode 100644
index 000000000000..edeec6562dcd
--- /dev/null
+++ b/src/Files.App/Views/Properties/SignaturesPage.xaml
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Files.App/Views/Properties/SignaturesPage.xaml.cs b/src/Files.App/Views/Properties/SignaturesPage.xaml.cs
new file mode 100644
index 000000000000..214f70bf2b54
--- /dev/null
+++ b/src/Files.App/Views/Properties/SignaturesPage.xaml.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Files Community
+// Licensed under the MIT License.
+
+using Files.App.ViewModels.Properties;
+using Microsoft.UI.Xaml.Navigation;
+
+namespace Files.App.Views.Properties
+{
+ public sealed partial class SignaturesPage : BasePropertiesPage
+ {
+ private SignaturesViewModel SignaturesViewModel { get; set; }
+
+ public SignaturesPage()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ var np = (PropertiesPageNavigationParameter)e.Parameter;
+ if (np.Parameter is ListedItem listedItem)
+ SignaturesViewModel = new(listedItem);
+
+ base.OnNavigatedTo(e);
+ }
+
+ protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
+ => Dispose();
+
+ public override Task SaveChangesAsync()
+ {
+ return Task.FromResult(true);
+ }
+
+ public override void Dispose()
+ {
+ SignaturesViewModel.Dispose();
+ }
+ }
+}
From 7d7d38619462bfa471100e75985509281863fb10 Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Sat, 26 Jul 2025 16:31:09 +0200
Subject: [PATCH 02/10] Retrieve signatures data
---
src/Files.App/Data/Items/CertNodeInfoItem.cs | 24 +
.../Data/Models/SignatureInfoItem.cs | 5 +-
.../Helpers/Win32/Win32Helper.Storage.cs | 4 +-
.../Helpers/Win32/Win32PInvoke.Methods.cs | 878 ++++++++-----
.../Helpers/Win32/Win32PInvoke.Structs.cs | 531 +++++---
.../Utils/Signatures/DigitalSignaturesUtil.cs | 1159 ++++++++++++++++-
.../Properties/SignaturesViewModel.cs | 3 +-
.../Views/Properties/SignaturesPage.xaml | 137 +-
8 files changed, 2116 insertions(+), 625 deletions(-)
create mode 100644 src/Files.App/Data/Items/CertNodeInfoItem.cs
diff --git a/src/Files.App/Data/Items/CertNodeInfoItem.cs b/src/Files.App/Data/Items/CertNodeInfoItem.cs
new file mode 100644
index 000000000000..1fdb3fed603f
--- /dev/null
+++ b/src/Files.App/Data/Items/CertNodeInfoItem.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Files Community
+// Licensed under the MIT License.
+
+namespace Files.App.Data.Items
+{
+ public class CertNodeInfoItem
+ {
+ public string IssuedTo { get; set; } = string.Empty;
+
+ public string IssuedBy { get; set; } = string.Empty;
+
+ public string Version { get; set; } = string.Empty;
+
+ public string SerialNumber { get; set; } = string.Empty;
+
+ public string Thumbprint { get; set; } = string.Empty;
+
+ public string ValidFrom { get; set; } = string.Empty;
+
+ public string ValidTo { get; set; } = string.Empty;
+
+ public string SignAlgorithm { get; set; } = string.Empty;
+ }
+}
diff --git a/src/Files.App/Data/Models/SignatureInfoItem.cs b/src/Files.App/Data/Models/SignatureInfoItem.cs
index 5a3593bb93f6..d9bc9154a7bb 100644
--- a/src/Files.App/Data/Models/SignatureInfoItem.cs
+++ b/src/Files.App/Data/Models/SignatureInfoItem.cs
@@ -60,12 +60,15 @@ public bool Verified
}
}
+ public List SignChain { get; }
+
public string Glyph => Verified ? "\uE930" : "\uEA39";
public ICommand OpenDetailsCommand { get; }
- public SignatureInfoItem()
+ public SignatureInfoItem(List chain)
{
+ SignChain = chain ?? new List();
OpenDetailsCommand = new AsyncRelayCommand(DoOpenDetails);
}
diff --git a/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs b/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs
index 7e878896a3f9..878db58ba0b4 100644
--- a/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs
+++ b/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs
@@ -904,13 +904,13 @@ public static SafeFileHandle OpenFileForRead(string filePath, bool readWrite = f
(uint)FILE_ACCESS_RIGHTS.FILE_GENERIC_READ | (uint)(readWrite ? FILE_ACCESS_RIGHTS.FILE_GENERIC_WRITE : 0u), (uint)(Win32PInvoke.FILE_SHARE_READ | (readWrite ? 0 : Win32PInvoke.FILE_SHARE_WRITE)), IntPtr.Zero, Win32PInvoke.OPEN_EXISTING, (uint)Win32PInvoke.File_Attributes.BackupSemantics | flags, IntPtr.Zero), true);
}
- public static bool GetFileDateModified(string filePath, out FILETIME dateModified)
+ public static bool GetFileDateModified(string filePath, out System.Runtime.InteropServices.ComTypes.FILETIME dateModified)
{
using var hFile = new SafeFileHandle(Win32PInvoke.CreateFileFromApp(filePath, (uint)FILE_ACCESS_RIGHTS.FILE_GENERIC_READ, Win32PInvoke.FILE_SHARE_READ, IntPtr.Zero, Win32PInvoke.OPEN_EXISTING, (uint)Win32PInvoke.File_Attributes.BackupSemantics, IntPtr.Zero), true);
return Win32PInvoke.GetFileTime(hFile.DangerousGetHandle(), out _, out _, out dateModified);
}
- public static bool SetFileDateModified(string filePath, FILETIME dateModified)
+ public static bool SetFileDateModified(string filePath, System.Runtime.InteropServices.ComTypes.FILETIME dateModified)
{
using var hFile = new SafeFileHandle(Win32PInvoke.CreateFileFromApp(filePath, (uint)FILE_ACCESS_RIGHTS.FILE_WRITE_ATTRIBUTES, 0, IntPtr.Zero, Win32PInvoke.OPEN_EXISTING, (uint)Win32PInvoke.File_Attributes.BackupSemantics, IntPtr.Zero), true);
return Win32PInvoke.SetFileTime(hFile.DangerousGetHandle(), new(), new(), dateModified);
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
index 06c875be2e25..e2d2c2a834b1 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
@@ -3,382 +3,546 @@
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
using System.Text;
using Windows.Win32.Foundation;
using Windows.Win32.System.Com;
namespace Files.App.Helpers
{
- public static partial class Win32PInvoke
- {
- public delegate void LpoverlappedCompletionRoutine(
- uint dwErrorCode,
- uint dwNumberOfBytesTransfered,
- OVERLAPPED lpOverlapped
- );
-
- public delegate void LPOVERLAPPED_COMPLETION_ROUTINE(
- uint dwErrorCode,
- uint dwNumberOfBytesTransfered,
- ref NativeOverlapped lpOverlapped
- );
-
- [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
- public static extern int RmRegisterResources(
- uint pSessionHandle,
- uint nFiles,
- string[] rgsFilenames,
- uint nApplications,
- [In] RM_UNIQUE_PROCESS[] rgApplications,
- uint nServices,
- string[] rgsServiceNames
- );
-
- [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
- public static extern int RmStartSession(
- out uint pSessionHandle,
- int dwSessionFlags,
- string strSessionKey
- );
-
- [DllImport("rstrtmgr.dll")]
- public static extern int RmEndSession(
- uint pSessionHandle
- );
-
- [DllImport("rstrtmgr.dll")]
- public static extern int RmGetList(
- uint dwSessionHandle,
- out uint pnProcInfoNeeded,
- ref uint pnProcInfo,
- [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
- ref uint lpdwRebootReasons
- );
-
- [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- public static extern IntPtr CreateEvent(
- IntPtr lpEventAttributes,
- bool bManualReset,
- bool bInitialState,
- string lpName
- );
-
- [DllImport("kernel32.dll")]
- public static extern bool SetEvent(
- IntPtr hEvent
- );
-
- [DllImport("ole32.dll")]
- public static extern uint CoWaitForMultipleObjects(
- uint dwFlags,
- uint dwMilliseconds,
- ulong nHandles,
- IntPtr[] pHandles,
- out uint dwIndex
- );
-
- [DllImport("shell32.dll")]
- public static extern IntPtr SHBrowseForFolder(
- ref BROWSEINFO lpbi
- );
-
- [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
- public static extern bool SHGetPathFromIDList(
- IntPtr pidl,
- [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath
- );
-
- [DllImport("api-ms-win-core-handle-l1-1-0.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool CloseHandle(
- IntPtr hObject
- );
-
- [DllImport("api-ms-win-core-io-l1-1-1.dll")]
- public static extern bool CancelIoEx(
- IntPtr hFile,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-synch-l1-2-0.dll", SetLastError = true)]
- public static extern uint WaitForSingleObjectEx(
- IntPtr hHandle,
- uint dwMilliseconds,
- bool bAlertable
- );
-
- [DllImport("api-ms-win-core-file-l2-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public unsafe static extern bool ReadDirectoryChangesW(
- IntPtr hDirectory,
- byte* lpBuffer,
- int nBufferLength,
- bool bWatchSubtree,
- int dwNotifyFilter,
- int* lpBytesReturned,
- ref OVERLAPPED lpOverlapped,
- LpoverlappedCompletionRoutine lpCompletionRoutine
- );
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
- public static extern IntPtr CreateFileFromAppW(
- string lpFileName,
- uint dwDesiredAccess,
- uint dwShareMode,
- IntPtr SecurityAttributes,
- uint dwCreationDisposition,
- uint dwFlagsAndAttributes,
- IntPtr hTemplateFile
- );
-
- [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
- public static extern bool DeviceIoControl(
- IntPtr hDevice,
- uint dwIoControlCode,
- IntPtr lpInBuffer,
- uint nInBufferSize,
- IntPtr lpOutBuffer,
- uint nOutBufferSize,
- out uint lpBytesReturned,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
- public static extern bool DeviceIoControl(
- IntPtr hDevice,
- uint dwIoControlCode,
- byte[] lpInBuffer,
- uint nInBufferSize,
- IntPtr lpOutBuffer,
- uint nOutBufferSize,
- out uint lpBytesReturned,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool DeviceIoControl(
- IntPtr hDevice,
- uint dwIoControlCode,
- IntPtr lpInBuffer,
- uint nInBufferSize,
- //IntPtr lpOutBuffer,
- out REPARSE_DATA_BUFFER outBuffer,
- uint nOutBufferSize,
- out uint lpBytesReturned,
- IntPtr lpOverlapped);
-
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
- public static extern int ToUnicodeEx(
- uint virtualKeyCode,
- uint scanCode,
- byte[] keyboardState,
- [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder receivingBuffer,
- int bufferSize,
- uint flags,
- IntPtr keyboardLayout
- );
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern IntPtr CreateFileFromApp(
- string lpFileName,
- uint dwDesiredAccess,
- uint dwShareMode,
- IntPtr SecurityAttributes,
- uint dwCreationDisposition,
- uint dwFlagsAndAttributes,
- IntPtr hTemplateFile
- );
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool GetFileAttributesExFromApp(
- string lpFileName,
- GET_FILEEX_INFO_LEVELS fInfoLevelId,
- out WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool SetFileAttributesFromApp(
- string lpFileName,
- FileAttributes dwFileAttributes);
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public unsafe static extern bool ReadFile(
- IntPtr hFile,
- byte* lpBuffer,
- int nBufferLength,
- int* lpBytesReturned,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public unsafe static extern bool WriteFile(
- IntPtr hFile,
- byte* lpBuffer,
- int nBufferLength,
- int* lpBytesWritten,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern bool WriteFileEx(
- IntPtr hFile,
- byte[] lpBuffer,
- uint nNumberOfBytesToWrite,
- [In] ref NativeOverlapped lpOverlapped,
- LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern bool GetFileTime(
- [In] IntPtr hFile,
- out FILETIME lpCreationTime,
- out FILETIME lpLastAccessTime,
- out FILETIME lpLastWriteTime
- );
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern bool SetFileTime(
- [In] IntPtr hFile,
- in FILETIME lpCreationTime,
- in FILETIME lpLastAccessTime,
- in FILETIME lpLastWriteTime
- );
-
- [DllImport("api-ms-win-core-file-l2-1-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern bool GetFileInformationByHandleEx(
- IntPtr hFile,
- FILE_INFO_BY_HANDLE_CLASS infoClass,
- out FILE_ID_BOTH_DIR_INFO dirInfo,
- uint dwBufferSize
- );
-
- [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
- public static extern IntPtr FindFirstStreamW(
- string lpFileName,
- StreamInfoLevels InfoLevel,
- [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData,
- uint dwFlags
- );
-
- [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool FindNextStreamW(
- IntPtr hndFindFile,
- [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData
- );
-
- [DllImport("api-ms-win-core-wow64-l1-1-1.dll", SetLastError = true)]
- public static extern bool IsWow64Process2(
- IntPtr process,
- out ushort processMachine,
- out ushort nativeMachine
- );
-
- [DllImport("api-ms-win-core-file-l1-1-0.dll", CharSet = CharSet.Unicode)]
- public static extern bool FindNextFile(
- IntPtr hFindFile,
- out WIN32_FIND_DATA lpFindFileData
- );
-
- [DllImport("api-ms-win-core-file-l1-1-0.dll")]
- public static extern bool FindClose(
- IntPtr hFindFile
- );
-
- [DllImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)]
- public static extern bool FileTimeToSystemTime(
- ref FILETIME lpFileTime,
- out SYSTEMTIME lpSystemTime
- );
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern IntPtr FindFirstFileExFromApp(
- string lpFileName,
- FINDEX_INFO_LEVELS fInfoLevelId,
- out WIN32_FIND_DATA lpFindFileData,
- FINDEX_SEARCH_OPS fSearchOp,
- IntPtr lpSearchFilter,
- int dwAdditionalFlags
- );
-
- [LibraryImport("shell32.dll", EntryPoint = "#865", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static partial bool IsElevationRequired(
- [MarshalAs(UnmanagedType.LPWStr)] string pszPath);
-
- [DllImport("shlwapi.dll", CallingConvention = CallingConvention.StdCall, PreserveSig = true, CharSet = CharSet.Unicode)]
- public static extern HRESULT SHCreateStreamOnFileEx(
- string pszFile,
- STGM grfMode,
- uint dwAttributes,
- uint fCreate,
- IntPtr pstmTemplate,
- out IntPtr ppstm
- );
-
- [DllImport("shell32.dll", CallingConvention = CallingConvention.StdCall, PreserveSig = true, CharSet = CharSet.Unicode)]
- public static extern HRESULT SHCreateItemFromParsingName(
- string pszPath,
- IntPtr pbc,
- ref Guid riid,
- out IntPtr ppv
- );
-
- [DllImport("ole32.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern HRESULT CoCreateInstance(
- ref Guid rclsid,
- IntPtr pUnkOuter,
- ClassContext dwClsContext,
- ref Guid riid,
- out IntPtr ppv
- );
-
- [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- public static extern uint RegisterApplicationRestart(
- string pwzCommandLine,
- int dwFlags
- );
-
- [DllImport("shell32.dll")]
- public static extern int SHGetKnownFolderPath(
- [MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
- uint dwFlags,
- IntPtr hToken,
- out IntPtr pszPath
- );
-
- [DllImport("wintrust.dll", CharSet = CharSet.Unicode, SetLastError = true)]
- private static extern uint WinVerifyTrust(
- IntPtr hwnd,
- [MarshalAs(UnmanagedType.LPStruct)] Guid pgActionID,
- IntPtr pWVTData
+ public static partial class Win32PInvoke
+ {
+ public delegate void LpoverlappedCompletionRoutine(
+ uint dwErrorCode,
+ uint dwNumberOfBytesTransfered,
+ OVERLAPPED lpOverlapped
+ );
+
+ public delegate void LPOVERLAPPED_COMPLETION_ROUTINE(
+ uint dwErrorCode,
+ uint dwNumberOfBytesTransfered,
+ ref NativeOverlapped lpOverlapped
+ );
+
+ [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
+ public static extern int RmRegisterResources(
+ uint pSessionHandle,
+ uint nFiles,
+ string[] rgsFilenames,
+ uint nApplications,
+ [In] RM_UNIQUE_PROCESS[] rgApplications,
+ uint nServices,
+ string[] rgsServiceNames
+ );
+
+ [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
+ public static extern int RmStartSession(
+ out uint pSessionHandle,
+ int dwSessionFlags,
+ string strSessionKey
+ );
+
+ [DllImport("rstrtmgr.dll")]
+ public static extern int RmEndSession(
+ uint pSessionHandle
+ );
+
+ [DllImport("rstrtmgr.dll")]
+ public static extern int RmGetList(
+ uint dwSessionHandle,
+ out uint pnProcInfoNeeded,
+ ref uint pnProcInfo,
+ [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
+ ref uint lpdwRebootReasons
+ );
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
+ public static extern IntPtr CreateEvent(
+ IntPtr lpEventAttributes,
+ bool bManualReset,
+ bool bInitialState,
+ string lpName
+ );
+
+ [DllImport("kernel32.dll")]
+ public static extern bool SetEvent(
+ IntPtr hEvent
+ );
+
+ [DllImport("ole32.dll")]
+ public static extern uint CoWaitForMultipleObjects(
+ uint dwFlags,
+ uint dwMilliseconds,
+ ulong nHandles,
+ IntPtr[] pHandles,
+ out uint dwIndex
+ );
+
+ [DllImport("shell32.dll")]
+ public static extern IntPtr SHBrowseForFolder(
+ ref BROWSEINFO lpbi
+ );
+
+ [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
+ public static extern bool SHGetPathFromIDList(
+ IntPtr pidl,
+ [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath
+ );
+
+ [DllImport("api-ms-win-core-handle-l1-1-0.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CloseHandle(
+ IntPtr hObject
+ );
+
+ [DllImport("api-ms-win-core-io-l1-1-1.dll")]
+ public static extern bool CancelIoEx(
+ IntPtr hFile,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-synch-l1-2-0.dll", SetLastError = true)]
+ public static extern uint WaitForSingleObjectEx(
+ IntPtr hHandle,
+ uint dwMilliseconds,
+ bool bAlertable
+ );
+
+ [DllImport("api-ms-win-core-file-l2-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public unsafe static extern bool ReadDirectoryChangesW(
+ IntPtr hDirectory,
+ byte* lpBuffer,
+ int nBufferLength,
+ bool bWatchSubtree,
+ int dwNotifyFilter,
+ int* lpBytesReturned,
+ ref OVERLAPPED lpOverlapped,
+ LpoverlappedCompletionRoutine lpCompletionRoutine
+ );
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern IntPtr CreateFileFromAppW(
+ string lpFileName,
+ uint dwDesiredAccess,
+ uint dwShareMode,
+ IntPtr SecurityAttributes,
+ uint dwCreationDisposition,
+ uint dwFlagsAndAttributes,
+ IntPtr hTemplateFile
+ );
+
+ [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool DeviceIoControl(
+ IntPtr hDevice,
+ uint dwIoControlCode,
+ IntPtr lpInBuffer,
+ uint nInBufferSize,
+ IntPtr lpOutBuffer,
+ uint nOutBufferSize,
+ out uint lpBytesReturned,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool DeviceIoControl(
+ IntPtr hDevice,
+ uint dwIoControlCode,
+ byte[] lpInBuffer,
+ uint nInBufferSize,
+ IntPtr lpOutBuffer,
+ uint nOutBufferSize,
+ out uint lpBytesReturned,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DeviceIoControl(
+ IntPtr hDevice,
+ uint dwIoControlCode,
+ IntPtr lpInBuffer,
+ uint nInBufferSize,
+ //IntPtr lpOutBuffer,
+ out REPARSE_DATA_BUFFER outBuffer,
+ uint nOutBufferSize,
+ out uint lpBytesReturned,
+ IntPtr lpOverlapped);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ public static extern int ToUnicodeEx(
+ uint virtualKeyCode,
+ uint scanCode,
+ byte[] keyboardState,
+ [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder receivingBuffer,
+ int bufferSize,
+ uint flags,
+ IntPtr keyboardLayout
+ );
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern IntPtr CreateFileFromApp(
+ string lpFileName,
+ uint dwDesiredAccess,
+ uint dwShareMode,
+ IntPtr SecurityAttributes,
+ uint dwCreationDisposition,
+ uint dwFlagsAndAttributes,
+ IntPtr hTemplateFile
+ );
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetFileAttributesExFromApp(
+ string lpFileName,
+ GET_FILEEX_INFO_LEVELS fInfoLevelId,
+ out WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetFileAttributesFromApp(
+ string lpFileName,
+ FileAttributes dwFileAttributes);
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public unsafe static extern bool ReadFile(
+ IntPtr hFile,
+ byte* lpBuffer,
+ int nBufferLength,
+ int* lpBytesReturned,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public unsafe static extern bool WriteFile(
+ IntPtr hFile,
+ byte* lpBuffer,
+ int nBufferLength,
+ int* lpBytesWritten,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern bool WriteFileEx(
+ IntPtr hFile,
+ byte[] lpBuffer,
+ uint nNumberOfBytesToWrite,
+ [In] ref NativeOverlapped lpOverlapped,
+ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern bool GetFileTime(
+ [In] IntPtr hFile,
+ out System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
+ out System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
+ out System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime
+ );
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern bool SetFileTime(
+ [In] IntPtr hFile,
+ in System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
+ in System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
+ in System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime
+ );
+
+ [DllImport("api-ms-win-core-file-l2-1-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern bool GetFileInformationByHandleEx(
+ IntPtr hFile,
+ FILE_INFO_BY_HANDLE_CLASS infoClass,
+ out FILE_ID_BOTH_DIR_INFO dirInfo,
+ uint dwBufferSize
+ );
+
+ [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern IntPtr FindFirstStreamW(
+ string lpFileName,
+ StreamInfoLevels InfoLevel,
+ [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData,
+ uint dwFlags
+ );
+
+ [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool FindNextStreamW(
+ IntPtr hndFindFile,
+ [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData
+ );
+
+ [DllImport("api-ms-win-core-wow64-l1-1-1.dll", SetLastError = true)]
+ public static extern bool IsWow64Process2(
+ IntPtr process,
+ out ushort processMachine,
+ out ushort nativeMachine
+ );
+
+ [DllImport("api-ms-win-core-file-l1-1-0.dll", CharSet = CharSet.Unicode)]
+ public static extern bool FindNextFile(
+ IntPtr hFindFile,
+ out WIN32_FIND_DATA lpFindFileData
+ );
+
+ [DllImport("api-ms-win-core-file-l1-1-0.dll")]
+ public static extern bool FindClose(
+ IntPtr hFindFile
+ );
+
+ [DllImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)]
+ public static extern bool FileTimeToSystemTime(
+ ref System.Runtime.InteropServices.ComTypes.FILETIME lpFileTime,
+ out SYSTEMTIME lpSystemTime
+ );
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr FindFirstFileExFromApp(
+ string lpFileName,
+ FINDEX_INFO_LEVELS fInfoLevelId,
+ out WIN32_FIND_DATA lpFindFileData,
+ FINDEX_SEARCH_OPS fSearchOp,
+ IntPtr lpSearchFilter,
+ int dwAdditionalFlags
+ );
+
+ [LibraryImport("shell32.dll", EntryPoint = "#865", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static partial bool IsElevationRequired(
+ [MarshalAs(UnmanagedType.LPWStr)] string pszPath);
+
+ [DllImport("shlwapi.dll", CallingConvention = CallingConvention.StdCall, PreserveSig = true, CharSet = CharSet.Unicode)]
+ public static extern HRESULT SHCreateStreamOnFileEx(
+ string pszFile,
+ STGM grfMode,
+ uint dwAttributes,
+ uint fCreate,
+ IntPtr pstmTemplate,
+ out IntPtr ppstm
);
- [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern bool CryptQueryObject(
+ [DllImport("shell32.dll", CallingConvention = CallingConvention.StdCall, PreserveSig = true, CharSet = CharSet.Unicode)]
+ public static extern HRESULT SHCreateItemFromParsingName(
+ string pszPath,
+ IntPtr pbc,
+ ref Guid riid,
+ out IntPtr ppv
+ );
+
+ [DllImport("ole32.dll", CallingConvention = CallingConvention.StdCall)]
+ public static extern HRESULT CoCreateInstance(
+ ref Guid rclsid,
+ IntPtr pUnkOuter,
+ ClassContext dwClsContext,
+ ref Guid riid,
+ out IntPtr ppv
+ );
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
+ public static extern uint RegisterApplicationRestart(
+ string pwzCommandLine,
+ int dwFlags
+ );
+
+ [DllImport("shell32.dll")]
+ public static extern int SHGetKnownFolderPath(
+ [MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
+ uint dwFlags,
+ IntPtr hToken,
+ out IntPtr pszPath
+ );
+
+ // crypt32.dll
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern uint CertGetNameStringA(
+ IntPtr pCertContext,
+ uint dwType,
+ uint dwFlags,
+ IntPtr pvTypePara,
+ IntPtr pszNameString,
+ uint cchNameString
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CertFreeCertificateContext(
+ IntPtr pCertContext
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptMsgGetParam(
+ IntPtr hCryptMsg,
+ uint dwParamType,
+ uint dwIndex,
+ IntPtr pParam,
+ ref uint dwOutSize
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptMsgClose(
+ IntPtr hCryptMsg
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr CryptMsgOpenToDecode(
+ uint dwMsgEncodingType,
+ uint dwFlags,
+ uint dwMsgType,
+ IntPtr hCryptProv,
+ IntPtr pRecipientInfo,
+ IntPtr pStreamInfo
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptMsgUpdate(
+ IntPtr hCryptMsg,
+ IntPtr pbData,
+ uint cbDatam,
+ bool fFinal
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr CertOpenStore(
+ IntPtr lpszStoreProvider,
+ uint dwEncodingType,
+ IntPtr hCryptProv,
+ uint dwFlags,
+ IntPtr pvPara
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptDecodeObject(
+ uint dwCertEncodingType,
+ IntPtr lpszStructType,
+ IntPtr pbEncoded,
+ uint cbEncoded,
+ uint dwFlags,
+ IntPtr pvStructInfo,
+ ref uint pcbStructInfo
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptBinaryToStringA(
+ IntPtr pbBinary,
+ uint cbBinary,
+ uint dwFlags,
+ IntPtr pszString,
+ ref uint pcchString
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr CertFindCertificateInStore(
+ IntPtr hCertStore,
+ uint dwCertEncodingType,
+ uint dwFindFlags,
+ uint dwFindType,
+ IntPtr pvFindPara,
+ IntPtr pPrevCertContext
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CertComparePublicKeyInfo(
+ uint dwCertEncodingType,
+ IntPtr pPublicKey1,
+ IntPtr pPublicKey2
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptQueryObject(
uint dwObjectType,
IntPtr pvObject,
uint dwExpectedContentTypeFlags,
uint dwExpectedFormatTypeFlags,
uint dwFlags,
- out uint pdwMsgAndCertEncodingType,
- out uint pdwContentType,
- out uint pdwFormatType,
- out IntPtr phCertStore,
- out IntPtr phMsg,
- out IntPtr ppvContext
+ ref uint pdwMsgAndCertEncodingType,
+ ref uint pdwContentType,
+ ref uint pdwFormatType,
+ ref IntPtr phCertStore,
+ ref IntPtr phMsg,
+ ref IntPtr ppvContext
);
- [DllImport("crypt32.dll", SetLastError = true)]
- private static extern bool CertCloseStore(
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CertCloseStore(
IntPtr hCertStore,
uint dwFlags
);
- [DllImport("crypt32.dll", SetLastError = true)]
- private static extern bool CryptMsgClose(
- IntPtr hCryptMsg
+ // wintrust.dll
+ [DllImport("wintrust.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptCATAdminCalcHashFromFileHandle(
+ IntPtr hFile,
+ ref uint pdwHash,
+ IntPtr pReserved,
+ uint dwFlags
+ );
+
+ [DllImport("wintrust.dll")]
+ public static extern long WinVerifyTrust(
+ IntPtr hwnd,
+ IntPtr pgActionID,
+ IntPtr pWVTData
+ );
+
+ // ncrypt.dll
+ [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool BCryptDestroyHash(
+ IntPtr hHash
+ );
+
+ [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern uint BCryptFinishHash(
+ IntPtr hHash,
+ IntPtr pbOutput,
+ uint cbOutput,
+ uint dwFlags
+ );
+
+ [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern uint BCryptOpenAlgorithmProvider(
+ out IntPtr phAlgorithm,
+ string pszAlgId,
+ string pszImplementation,
+ uint dwFlags
+ );
+
+ [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern uint BCryptCloseAlgorithmProvider(
+ IntPtr hAlgorithm,
+ uint dwFlags
+ );
+
+ [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern uint BCryptCreateHash(
+ IntPtr hAlgorithm,
+ out IntPtr hHash,
+ IntPtr pbHashObject,
+ uint cbHashObject,
+ IntPtr pbSecret,
+ uint cbSecret,
+ uint flags
+ );
+
+
+ [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern uint BCryptHashData(
+ IntPtr hHash,
+ IntPtr pbInput,
+ uint cbInput,
+ uint dwFlags
+ );
+
+ // kernel32.dll
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool FileTimeToSystemTime(
+ IntPtr lpFileTime,
+ IntPtr lpSystemTime
+ );
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool FileTimeToLocalFileTime(
+ IntPtr lpFileTime,
+ IntPtr lpLocalFileTime
+ );
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool SystemTimeToFileTime(
+ IntPtr lpSystemTime,
+ IntPtr lpFileTime
);
}
}
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
index d54e6ee441e7..7ed7f1305488 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
@@ -3,200 +3,345 @@
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
namespace Files.App.Helpers
{
- public static partial class Win32PInvoke
- {
- [StructLayout(LayoutKind.Sequential)]
- public struct RM_UNIQUE_PROCESS
- {
- public int dwProcessId;
- public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct RM_PROCESS_INFO
- {
- public RM_UNIQUE_PROCESS Process;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
- public string strAppName;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
- public string strServiceShortName;
-
- public RM_APP_TYPE ApplicationType;
- public uint AppStatus;
- public uint TSSessionId;
- [MarshalAs(UnmanagedType.Bool)]
- public bool bRestartable;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct BROWSEINFO
- {
- public IntPtr hwndOwner;
- public IntPtr pidlRoot;
- public string pszDisplayName;
- public string lpszTitle;
- public uint ulFlags;
- public IntPtr lpfn;
- public int lParam;
- public IntPtr iImage;
- }
-
- public unsafe struct OVERLAPPED
- {
- public IntPtr Internal;
- public IntPtr InternalHigh;
- public Union PointerAndOffset;
- public IntPtr hEvent;
-
- [StructLayout(LayoutKind.Explicit)]
- public struct Union
- {
- [FieldOffset(0)] public void* IntPtr;
- [FieldOffset(0)] public OffsetPair Offset;
-
- public struct OffsetPair { public uint Offset; public uint OffsetHigh; }
- }
- }
-
- public unsafe struct FILE_NOTIFY_INFORMATION
- {
- public uint NextEntryOffset;
- public uint Action;
- public uint FileNameLength;
- public fixed char FileName[1];
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct REPARSE_DATA_BUFFER
- {
- public uint ReparseTag;
- public short ReparseDataLength;
- public short Reserved;
- public short SubsNameOffset;
- public short SubsNameLength;
- public short PrintNameOffset;
- public short PrintNameLength;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_REPARSE_DATA_BUFFER_SIZE)]
- public char[] PathBuffer;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct WIN32_FILE_ATTRIBUTE_DATA
- {
- public FileAttributes dwFileAttributes;
- public FILETIME ftCreationTime;
- public FILETIME ftLastAccessTime;
- public FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct FILE_ID_BOTH_DIR_INFO
- {
- public uint NextEntryOffset;
- public uint FileIndex;
- public long CreationTime;
- public long LastAccessTime;
- public long LastWriteTime;
- public long ChangeTime;
- public long EndOfFile;
- public long AllocationSize;
- public uint FileAttributes;
- public uint FileNameLength;
- public uint EaSize;
- public char ShortNameLength;
- [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 12)]
- public string ShortName;
- public long FileId;
- [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
- public string FileName;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
- public struct FILE_STREAM_INFO
- {
- public uint NextEntryOffset;
- public uint StreamNameLength;
- public long StreamSize;
- public long StreamAllocationSize;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
- public string StreamName;
- }
-
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public sealed class WIN32_FIND_STREAM_DATA
- {
- public long StreamSize;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 296)]
- public string cStreamName;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct SID_AND_ATTRIBUTES
- {
- public IntPtr Sid;
-
- public uint Attributes;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct SYSTEMTIME
- {
- [MarshalAs(UnmanagedType.U2)] public short Year;
- [MarshalAs(UnmanagedType.U2)] public short Month;
- [MarshalAs(UnmanagedType.U2)] public short DayOfWeek;
- [MarshalAs(UnmanagedType.U2)] public short Day;
- [MarshalAs(UnmanagedType.U2)] public short Hour;
- [MarshalAs(UnmanagedType.U2)] public short Minute;
- [MarshalAs(UnmanagedType.U2)] public short Second;
- [MarshalAs(UnmanagedType.U2)] public short Milliseconds;
-
- public SYSTEMTIME(DateTime dt)
- {
- dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC
- Year = (short)dt.Year;
- Month = (short)dt.Month;
- DayOfWeek = (short)dt.DayOfWeek;
- Day = (short)dt.Day;
- Hour = (short)dt.Hour;
- Minute = (short)dt.Minute;
- Second = (short)dt.Second;
- Milliseconds = (short)dt.Millisecond;
- }
-
- public DateTime ToDateTime()
- {
- return new(Year, Month, Day, Hour, Minute, Second, Milliseconds, DateTimeKind.Utc);
- }
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
- public struct WIN32_FIND_DATA
- {
- public uint dwFileAttributes;
-
- public FILETIME ftCreationTime;
- public FILETIME ftLastAccessTime;
- public FILETIME ftLastWriteTime;
-
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
- public string cFileName;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
- }
+ public static partial class Win32PInvoke
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RM_UNIQUE_PROCESS
+ {
+ public int dwProcessId;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct RM_PROCESS_INFO
+ {
+ public RM_UNIQUE_PROCESS Process;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
+ public string strAppName;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
+ public string strServiceShortName;
+
+ public RM_APP_TYPE ApplicationType;
+ public uint AppStatus;
+ public uint TSSessionId;
+ [MarshalAs(UnmanagedType.Bool)]
+ public bool bRestartable;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct BROWSEINFO
+ {
+ public IntPtr hwndOwner;
+ public IntPtr pidlRoot;
+ public string pszDisplayName;
+ public string lpszTitle;
+ public uint ulFlags;
+ public IntPtr lpfn;
+ public int lParam;
+ public IntPtr iImage;
+ }
+
+ public unsafe struct OVERLAPPED
+ {
+ public IntPtr Internal;
+ public IntPtr InternalHigh;
+ public Union PointerAndOffset;
+ public IntPtr hEvent;
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct Union
+ {
+ [FieldOffset(0)] public void* IntPtr;
+ [FieldOffset(0)] public OffsetPair Offset;
+
+ public struct OffsetPair { public uint Offset; public uint OffsetHigh; }
+ }
+ }
+
+ public unsafe struct FILE_NOTIFY_INFORMATION
+ {
+ public uint NextEntryOffset;
+ public uint Action;
+ public uint FileNameLength;
+ public fixed char FileName[1];
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct REPARSE_DATA_BUFFER
+ {
+ public uint ReparseTag;
+ public short ReparseDataLength;
+ public short Reserved;
+ public short SubsNameOffset;
+ public short SubsNameLength;
+ public short PrintNameOffset;
+ public short PrintNameLength;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_REPARSE_DATA_BUFFER_SIZE)]
+ public char[] PathBuffer;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WIN32_FILE_ATTRIBUTE_DATA
+ {
+ public FileAttributes dwFileAttributes;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct FILE_ID_BOTH_DIR_INFO
+ {
+ public uint NextEntryOffset;
+ public uint FileIndex;
+ public long CreationTime;
+ public long LastAccessTime;
+ public long LastWriteTime;
+ public long ChangeTime;
+ public long EndOfFile;
+ public long AllocationSize;
+ public uint FileAttributes;
+ public uint FileNameLength;
+ public uint EaSize;
+ public char ShortNameLength;
+ [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 12)]
+ public string ShortName;
+ public long FileId;
+ [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
+ public string FileName;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
+ public struct FILE_STREAM_INFO
+ {
+ public uint NextEntryOffset;
+ public uint StreamNameLength;
+ public long StreamSize;
+ public long StreamAllocationSize;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string StreamName;
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public sealed class WIN32_FIND_STREAM_DATA
+ {
+ public long StreamSize;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 296)]
+ public string cStreamName;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SID_AND_ATTRIBUTES
+ {
+ public IntPtr Sid;
+
+ public uint Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SYSTEMTIME
+ {
+ [MarshalAs(UnmanagedType.U2)] public short Year;
+ [MarshalAs(UnmanagedType.U2)] public short Month;
+ [MarshalAs(UnmanagedType.U2)] public short DayOfWeek;
+ [MarshalAs(UnmanagedType.U2)] public short Day;
+ [MarshalAs(UnmanagedType.U2)] public short Hour;
+ [MarshalAs(UnmanagedType.U2)] public short Minute;
+ [MarshalAs(UnmanagedType.U2)] public short Second;
+ [MarshalAs(UnmanagedType.U2)] public short Milliseconds;
+
+ public SYSTEMTIME(DateTime dt)
+ {
+ dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC
+ Year = (short)dt.Year;
+ Month = (short)dt.Month;
+ DayOfWeek = (short)dt.DayOfWeek;
+ Day = (short)dt.Day;
+ Hour = (short)dt.Hour;
+ Minute = (short)dt.Minute;
+ Second = (short)dt.Second;
+ Milliseconds = (short)dt.Millisecond;
+ }
+
+ public DateTime ToDateTime()
+ {
+ return new(Year, Month, Day, Hour, Minute, Second, Milliseconds, DateTimeKind.Utc);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct WIN32_FIND_DATA
+ {
+ public uint dwFileAttributes;
+
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
+
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string cFileName;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPTOAPI_BLOB
+ {
+ public uint cbData;
+ public IntPtr pbData;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CMSG_SIGNER_INFO
+ {
+ public uint dwVersion;
+ public CRYPTOAPI_BLOB Issuer;
+ public CRYPTOAPI_BLOB SerialNumber;
+ public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
+ public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
+ public CRYPTOAPI_BLOB EncryptedHash;
+ public CRYPTOAPI_BLOB AuthAttrs;
+ public CRYPTOAPI_BLOB UnauthAttrs;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SignDataHandle
+ {
+ public uint dwObjSize;
+ public IntPtr pSignerInfo;
+ public IntPtr hCertStoreHandle;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPT_ATTRIBUTE
+ {
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string pszObjId;
+ public uint cValue;
+ public IntPtr rgValue;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct FILETIME
+ {
+ public uint dwLowDateTime;
+ public uint dwHighDateTime;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPT_BIT_BLOB
+ {
+ private readonly uint cbData;
+ private readonly IntPtr pbData;
+ private readonly uint cUnusedBits;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_ALT_NAME_INFO
+ {
+ public uint cAltEntry;
+ public IntPtr rgAltEntry;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRL_DIST_POINT_NAME
+ {
+ public uint dwDistPointNameChoice;
+ public CERT_ALT_NAME_INFO FullName;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_CONTEXT
+ {
+ public uint dwCertEncodingType;
+ public IntPtr pbCertEncoded;
+ public uint cbCertEncoded;
+ public IntPtr pCertInfo;
+ public IntPtr hCertStore;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_INFO
+ {
+ public uint dwVersion;
+ public CRYPTOAPI_BLOB SerialNumber;
+ public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
+ public CRYPTOAPI_BLOB Issuer;
+ public FILETIME NotBefore;
+ public FILETIME NotAfter;
+ public CRYPTOAPI_BLOB Subject;
+ public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
+ public CRYPT_BIT_BLOB IssuerUniqueId;
+ public CRYPT_BIT_BLOB SubjectUniqueId;
+ public uint cExtension;
+ public IntPtr rgExtension;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPT_ALGORITHM_IDENTIFIER
+ {
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string pszObjId;
+ public CRYPTOAPI_BLOB Parameters;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_PUBLIC_KEY_INFO
+ {
+ public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
+ public CRYPTOAPI_BLOB PublicKey;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CATALOG_INFO
+ {
+ public uint cbStruct;
+ public char[] wszCatalogFile = new char[256];
+
+ public CATALOG_INFO()
+ {
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WINTRUST_FILE_INFO
+ {
+ public uint cbStruct;
+ public IntPtr pcwszFilePath;
+ public IntPtr hFile;
+ public IntPtr pgKnownSubject;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WINTRUST_DATA
+ {
+ public uint cbStruct;
+ public IntPtr pPolicyCallbackData;
+ public IntPtr pSIPClientData;
+ public uint dwUIChoice;
+ public uint fdwRevocationChecks;
+ public uint dwUnionChoice;
+ public IntPtr pFile;
+ public uint dwStateAction;
+ public IntPtr hVWTStateData;
+ public IntPtr pwszURLReference;
+ public uint dwProvFlags;
+ public uint dwUIContext;
+ public IntPtr pSignatureSettings;
+ }
+ }
}
diff --git a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
index 97707cab1fb3..fbb2b2825cf9 100644
--- a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
+++ b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
@@ -1,15 +1,1168 @@
// Copyright (c) Files Community
// Licensed under the MIT License.
+using System.Runtime.InteropServices;
+using System.Text;
+using static Files.App.Helpers.Win32PInvoke;
+
namespace Files.App.Utils.Signatures
{
public static class DigitalSignaturesUtil
{
- public static List GetSignaturesOfItem(string filePath)
+ // Constants
+ private const int SHA1LEN = 20;
+ private const int MD5_LEN = 16;
+
+ private const uint CALG_SHA1 = 0x00008004;
+ private const uint CALG_MD5 = 0x00008003;
+
+ // - OIDs
+ private const string szOID_NESTED_SIGNATURE = "1.3.6.1.4.1.311.2.4.1";
+ private const string szOID_RSA_counterSign = "1.2.840.113549.1.9.6";
+ private const string szOID_RSA_signingTime = "1.2.840.113549.1.9.5";
+ private const string szOID_RFC3161_counterSign = "1.3.6.1.4.1.311.3.3.1";
+ private const string szOID_OIWSEC_sha1 = "1.3.14.3.2.26";
+ private const string szOID_RSA_MD5 = "1.2.840.113549.2.5";
+ private const string szOID_NIST_sha256 = "2.16.840.1.101.3.4.2.1";
+ private const string szOID_RSA_SHA1RSA = "1.2.840.113549.1.1.5";
+ private const string szOID_OIWSEC_sha1RSASign = "1.3.14.3.2.29";
+ private const string szOID_RSA_MD5RSA = "1.2.840.113549.1.1.4";
+ private const string szOID_OIWSEC_md5RSA = "1.3.14.3.2.3";
+ private const string szOID_RSA_MD2RSA = "1.2.840.113549.1.1.2";
+ private const string szOID_RSA_SHA256RSA = "1.2.840.113549.1.1.11";
+
+ // - Flags
+ private const uint CRYPT_STRING_HEX = 0x00000004;
+ private const uint CERT_NAME_SIMPLE_DISPLAY_TYPE = 4;
+ private const uint CERT_FIND_SUBJECT_NAME = 131079;
+ private const uint CERT_FIND_ISSUER_NAME = 131076;
+ private const uint CERT_QUERY_OBJECT_FILE = 0x00000001;
+ private const uint CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = 0x00000400;
+ private const uint CERT_QUERY_FORMAT_FLAG_BINARY = 0x00000002;
+ private const uint CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000;
+ private const IntPtr CERT_STORE_PROV_SYSTEM = 10;
+ private const IntPtr CERT_STORE_PROV_MSG = 1;
+
+ private const uint PKCS_7_ASN_ENCODING = 0x00010000;
+ private const uint CRYPT_ASN_ENCODING = 0x00000001;
+
+ private const IntPtr PKCS7_SIGNER_INFO = 500;
+ private const IntPtr PKCS_UTC_TIME = 17;
+
+ private const uint CMSG_SIGNER_INFO_PARAM = 6;
+
+ // - Version numbers
+ private const uint CERT_V1 = 0;
+ private const uint CERT_V2 = 1;
+ private const uint CERT_V3 = 2;
+
+ private static readonly byte[] SG_ProtoCoded = [
+ 0x30, 0x82
+ ];
+
+ private static readonly byte[] SG_SignedData = [
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02
+ ];
+
+ private static readonly IDateTimeFormatter formatter = Ioc.Default.GetRequiredService();
+
+ public static void LoadItemSignatures(string filePath, ObservableCollection signatures)
+ {
+ var signChain = new List();
+ GetSignerCertificateInfo(filePath, signChain);
+
+ foreach (var signNode in signChain)
+ {
+ if (signNode.CertChain.Count == 0)
+ continue;
+
+ var signatureInfo = new SignatureInfoItem(signNode.CertChain)
+ {
+ Version = signNode.Version,
+ IssuedBy = signNode.CertChain[0].IssuedBy,
+ IssuedTo = signNode.CertChain[0].IssuedTo,
+ ValidFromTimestamp = signNode.CertChain[0].ValidFrom,
+ ValidToTimestamp = signNode.CertChain[0].ValidTo,
+ VerifiedTimestamp = signNode.CounterSign.TimeStamp,
+ Verified = signNode.IsValid,
+ };
+ signatures.Add(signatureInfo);
+ }
+ }
+
+ private static bool CalculateSignSerial(IntPtr pbData, uint cbData, CertNodeInfoItem info)
+ {
+ uint size = 0;
+ var abSerial = Marshal.AllocHGlobal(0x400);
+ IntPtr nameBuff = IntPtr.Zero;
+ info.SerialNumber = string.Empty;
+
+ try
+ {
+ for (var i = 0; i < cbData && i < 0x400; i++)
+ {
+ Marshal.WriteByte(
+ abSerial,
+ i,
+ Marshal.ReadByte(pbData, (int)(cbData - 1 - i))
+ );
+ }
+
+ var result = CryptBinaryToStringA(abSerial, cbData, CRYPT_STRING_HEX, IntPtr.Zero, ref size);
+ if (!result)
+ return false;
+
+ nameBuff = Marshal.AllocHGlobal(0x400);
+ result = CryptBinaryToStringA(abSerial, cbData, CRYPT_STRING_HEX, nameBuff, ref size);
+ if (!result)
+ return false;
+
+ StringBuilder builder = new(Marshal.PtrToStringAnsi(nameBuff));
+ var iter2 = 0;
+ for (var iter1 = 0; iter1 < size; iter1++)
+ {
+ if (!char.IsWhiteSpace(builder[iter1]))
+ builder[iter2++] = builder[iter1];
+ }
+
+ builder.Remove(iter2, builder.Length - iter2);
+ info.SerialNumber = StripString(builder.ToString());
+
+ return true;
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(abSerial);
+ if (nameBuff != IntPtr.Zero)
+ Marshal.FreeHGlobal(nameBuff);
+ }
+ }
+
+ private static bool GetSignerSignatureInfo(
+ IntPtr hSystemStore,
+ IntPtr hCertStore,
+ IntPtr pOrigContext,
+ ref IntPtr pCurrContext,
+ SignNodeInfo signNode)
{
- var signatures = new List();
+ var currContext = Marshal.PtrToStructure(pCurrContext);
+ var pCertInfo = currContext.pCertInfo;
+ var certNode = new CertNodeInfoItem();
+ var certInfo = Marshal.PtrToStructure(pCertInfo);
+ var szObjId = certInfo.SignatureAlgorithm.pszObjId;
+
+ CalculateCertAlgorithm(szObjId, certNode);
+ CalculateSignSerial(certInfo.SerialNumber.pbData, certInfo.SerialNumber.cbData, certNode);
+ (_, certNode.Version) = CalculateSignVersion(certInfo.dwVersion);
+ GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, certNode);
+ GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 1, certNode);
+ CalculateHashOfBytes(
+ currContext.pbCertEncoded,
+ CALG_SHA1,
+ currContext.cbCertEncoded,
+ certNode
+ );
+
+ var pft = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(certInfo.NotBefore, pft, false);
+ certNode.ValidFrom = TimeToString(pft);
+ Marshal.StructureToPtr(certInfo.NotAfter, pft, false);
+ certNode.ValidTo = TimeToString(pft);
+ Marshal.FreeHGlobal(pft);
+
+ signNode.CertChain.Add(certNode);
+
+ var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(certInfo.Issuer, pIssuer, false);
+ pCurrContext = CertFindCertificateInStore(
+ hCertStore,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ pIssuer,
+ IntPtr.Zero
+ );
+
+ if (pCurrContext == IntPtr.Zero)
+ {
+ pCurrContext = CertFindCertificateInStore(
+ hSystemStore,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ pIssuer,
+ IntPtr.Zero
+ );
+ }
+
+ Marshal.FreeHGlobal(pIssuer);
+ if (pCurrContext == IntPtr.Zero)
+ return false;
+
+ var pCurrPublicKey = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(certInfo.SubjectPublicKeyInfo, pCurrPublicKey, false);
+
+ var origContext = Marshal.PtrToStructure(pOrigContext);
+ var origInfo = Marshal.PtrToStructure(origContext.pCertInfo);
+ var pOrigPublicKey = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(origInfo.SubjectPublicKeyInfo, pOrigPublicKey, false);
+
+ var result = CertComparePublicKeyInfo(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ pCurrPublicKey,
+ pOrigPublicKey
+ );
+
+ Marshal.FreeHGlobal(pCurrPublicKey);
+ Marshal.FreeHGlobal(pOrigPublicKey);
+
+ return !result;
+ }
+
+ private static bool GetSignerCertificateInfo(string fileName, List signChain)
+ {
+ var succeded = false;
+ var authSignData = new SignDataHandle();
+ var signDataChain = new List();
+ signChain.Clear();
+
+ var pRoot = Marshal.StringToHGlobalAuto("Root");
+ var hSystemStore = CertOpenStore(
+ CERT_STORE_PROV_SYSTEM,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ IntPtr.Zero,
+ CERT_SYSTEM_STORE_CURRENT_USER,
+ pRoot
+ );
+ Marshal.FreeHGlobal(pRoot);
+ if (hSystemStore == IntPtr.Zero)
+ return false;
+
+ var hAuthCryptMsg = IntPtr.Zero;
+ uint encoding = 0;
+ var pDummy = IntPtr.Zero;
+ uint dummy = 0;
+ var pFileName = Marshal.StringToHGlobalAuto(fileName);
+ var result = CryptQueryObject(
+ CERT_QUERY_OBJECT_FILE,
+ pFileName,
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+ CERT_QUERY_FORMAT_FLAG_BINARY,
+ 0,
+ ref encoding,
+ ref dummy,
+ ref dummy,
+ ref authSignData.hCertStoreHandle,
+ ref hAuthCryptMsg,
+ ref pDummy
+ );
+ Marshal.FreeHGlobal(pFileName);
+
+ if (!result)
+ {
+ CertCloseStore(hSystemStore, 0);
+ return false;
+ }
+
+ result = CustomCryptMsgGetParam(
+ hAuthCryptMsg,
+ CMSG_SIGNER_INFO_PARAM,
+ 0,
+ ref authSignData.pSignerInfo,
+ ref authSignData.dwObjSize
+ );
+ CryptMsgClose(hAuthCryptMsg);
+ hAuthCryptMsg = IntPtr.Zero;
+ if (!result)
+ {
+ CertCloseStore(authSignData.hCertStoreHandle, 0);
+ CertCloseStore(hSystemStore, 0);
+
+ return false;
+ }
+
+ signDataChain.Add(authSignData);
+ GetNestedSignerInfo(ref authSignData, signDataChain);
+
+ for (var i = 0; i < signDataChain.Count; i++)
+ {
+ var pCurrContext = IntPtr.Zero;
+ var pCounterSigner = IntPtr.Zero;
+ var signNode = new SignNodeInfo();
+
+ GetCounterSignerInfo(signDataChain[i].pSignerInfo, ref pCounterSigner);
+ if (pCounterSigner != IntPtr.Zero)
+ GetCounterSignerData(pCounterSigner, signNode.CounterSign);
+ else
+ GetGeneralizedNameAndTimeStamp(signDataChain[i].pSignerInfo, signNode.CounterSign);
+
+ var signerInfo = Marshal.PtrToStructure(signDataChain[i].pSignerInfo);
+ var szObjId = signerInfo.HashAlgorithm.pszObjId;
+ CalculateDigestAlgorithm(szObjId, signNode);
+ (_, signNode.Version) = CalculateSignVersion(signerInfo.dwVersion);
+
+ var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(signerInfo.Issuer, pIssuer, false);
+ pCurrContext = CertFindCertificateInStore(
+ signDataChain[i].hCertStoreHandle,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ CERT_FIND_ISSUER_NAME,
+ pIssuer,
+ IntPtr.Zero
+ );
+ Marshal.FreeHGlobal(pIssuer);
+
+ result = pCurrContext != IntPtr.Zero;
+ while (result)
+ {
+ var pOrigContext = pCurrContext;
+ result = GetSignerSignatureInfo(
+ hSystemStore,
+ signDataChain[i].hCertStoreHandle,
+ pOrigContext,
+ ref pCurrContext,
+ signNode
+ );
+ CertFreeCertificateContext(pOrigContext);
+ }
+
+ if (pCurrContext != IntPtr.Zero)
+ CertFreeCertificateContext(pCurrContext);
+
+ if (pCounterSigner != IntPtr.Zero)
+ Marshal.FreeHGlobal(pCounterSigner);
+
+ if (signDataChain[i].pSignerInfo != IntPtr.Zero)
+ Marshal.FreeHGlobal(signDataChain[i].pSignerInfo);
+
+ if (signDataChain[i].hCertStoreHandle != IntPtr.Zero)
+ CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
- return signatures;
+ succeded = true;
+ signNode.IsValid = VerifyySignature(fileName);
+ signChain.Add(signNode);
+ }
+
+ CertCloseStore(hSystemStore, 0);
+ return succeded;
+ }
+
+ private static bool CustomCryptCalcFileHash(
+ IntPtr fileHandle,
+ ref IntPtr szBuffer,
+ ref uint hashSize)
+ {
+ hashSize = 0;
+ CryptCATAdminCalcHashFromFileHandle(
+ fileHandle,
+ ref hashSize,
+ IntPtr.Zero,
+ 0
+ );
+ if (hashSize == 0)
+ return false;
+
+ szBuffer = Marshal.AllocHGlobal((int)hashSize * sizeof(byte));
+ var result = CryptCATAdminCalcHashFromFileHandle(
+ fileHandle,
+ ref hashSize,
+ szBuffer,
+ 0
+ );
+ if (!result)
+ Marshal.FreeHGlobal(szBuffer);
+
+ return result;
+ }
+
+ private static bool VerifyySignature(string certPath)
+ {
+ var actionGuid = new Guid("{00AAC56B-CD44-11D0-8CC2-00C04FC295EE}");
+ var guidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(actionGuid));
+ Marshal.StructureToPtr(actionGuid, guidPtr, false);
+
+ var sFileInfo = Marshal.SizeOf();
+ var fileInfo = new WINTRUST_FILE_INFO
+ {
+ cbStruct = (uint)sFileInfo,
+ pcwszFilePath = Marshal.StringToCoTaskMemAuto(certPath),
+ hFile = IntPtr.Zero,
+ pgKnownSubject = IntPtr.Zero
+ };
+ var filePtr = Marshal.AllocHGlobal(sFileInfo);
+ Marshal.StructureToPtr(fileInfo, filePtr, false);
+
+ var sData = Marshal.SizeOf();
+ var wintrustData = new WINTRUST_DATA
+ {
+ cbStruct = (uint)sData,
+ pPolicyCallbackData = IntPtr.Zero,
+ pSIPClientData = IntPtr.Zero,
+ dwUIChoice = 2, // Display no UI
+ fdwRevocationChecks = 0, // No revocation checking
+ dwUnionChoice = 1, // Verify an embedded signature on a file
+ dwStateAction = 1, // Verify action
+ hVWTStateData = IntPtr.Zero,
+ pwszURLReference = IntPtr.Zero,
+ dwUIContext = 0,
+ pFile = filePtr
+ };
+ var dataPtr = Marshal.AllocHGlobal(sData);
+ Marshal.StructureToPtr(wintrustData, dataPtr, false);
+
+ try
+ {
+ var res = WinVerifyTrust(IntPtr.Zero, guidPtr, dataPtr);
+
+ // Release hWVTStateData
+ wintrustData.dwStateAction = 2; // Close
+ Marshal.StructureToPtr(wintrustData, dataPtr, true);
+ WinVerifyTrust(IntPtr.Zero, guidPtr, dataPtr);
+
+ return res == 0;
+ }
+ finally
+ {
+ if (fileInfo.pcwszFilePath != IntPtr.Zero)
+ Marshal.FreeCoTaskMem(fileInfo.pcwszFilePath);
+
+ Marshal.FreeHGlobal(guidPtr);
+ Marshal.FreeHGlobal(filePtr);
+ Marshal.FreeHGlobal(dataPtr);
+ }
+ }
+
+ private static bool GetCounterSignerInfo(IntPtr pSignerInfo, ref IntPtr pTargetSigner)
+ {
+ uint objSize = 0;
+ int n;
+
+ if (pSignerInfo == IntPtr.Zero)
+ return false;
+
+ try
+ {
+ var res = TryGetUnauthAttr(pSignerInfo, szOID_RSA_counterSign, out var attr);
+ if (!res)
+ return false;
+
+ var rgValue = Marshal.PtrToStructure(attr.rgValue);
+ var result = CryptDecodeObject(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ PKCS7_SIGNER_INFO,
+ rgValue.pbData,
+ rgValue.cbData,
+ 0,
+ IntPtr.Zero,
+ ref objSize
+ );
+ if (!result)
+ return false;
+
+ pTargetSigner = Marshal.AllocHGlobal((int)objSize * sizeof(byte));
+ if (pTargetSigner == IntPtr.Zero)
+ return false;
+
+ result = CryptDecodeObject(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ PKCS7_SIGNER_INFO,
+ rgValue.pbData,
+ rgValue.cbData,
+ 0,
+ pTargetSigner,
+ ref objSize
+ );
+ if (!result)
+ return false;
+ }
+ finally
+ {
+ }
+
+ return true;
+ }
+
+ private static bool GetCounterSignerData(IntPtr pSignerInfo, SignCounterSign counterSign)
+ {
+ var res = TryGetAuthAttr(pSignerInfo, szOID_RSA_signingTime, out var attr);
+ if (!res)
+ return false;
+
+ var rgValue = Marshal.PtrToStructure(attr.rgValue);
+
+ var data = (uint)Marshal.SizeOf();
+ var ft = Marshal.AllocHGlobal((int)data);
+ IntPtr lft = IntPtr.Zero;
+ IntPtr st = IntPtr.Zero;
+
+ try
+ {
+ var pStructType = Marshal.StringToHGlobalUni(szOID_RSA_signingTime);
+ var result = CryptDecodeObject(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ PKCS_UTC_TIME,
+ rgValue.pbData,
+ rgValue.cbData,
+ 0,
+ ft,
+ ref data
+ );
+ Marshal.FreeHGlobal(pStructType);
+ if (!result)
+ return false;
+
+ lft = Marshal.AllocHGlobal((int)data);
+ st = Marshal.AllocHGlobal(Marshal.SizeOf());
+ FileTimeToLocalFileTime(ft, lft);
+ FileTimeToSystemTime(lft, st);
+ counterSign.TimeStamp = TimeToString(IntPtr.Zero, st);
+
+ return true;
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(ft);
+ if (lft != IntPtr.Zero)
+ Marshal.FreeHGlobal(lft);
+
+ if (st != IntPtr.Zero)
+ Marshal.FreeHGlobal(st);
+ }
+ }
+
+ private static bool ParseDERFindType(
+ int typeSearch,
+ IntPtr pbSignature,
+ uint size,
+ ref uint positionFound,
+ ref uint lengthFound)
+ {
+ uint position = 0;
+ uint sizeFound = 0;
+ uint bytesParsed = 0;
+ var iType = 0;
+ var iClass = 0;
+ positionFound = 0;
+ lengthFound = 0;
+ if (pbSignature == IntPtr.Zero)
+ return false;
+
+ while (size > position)
+ {
+ if (!SafeToReadNBytes(size, position, 2))
+ return false;
+
+ ParseDERType(Marshal.ReadByte(pbSignature, (int)position), ref iType, ref iClass);
+ switch (iType)
+ {
+ case 0x05: // Null
+ ++position;
+ if (Marshal.ReadByte(pbSignature, (int)position) != 0x00)
+ return false;
+
+ ++position;
+ break;
+
+ case 0x06: // Object Identifier
+ ++position;
+ var val = Marshal.ReadByte(pbSignature, (int)position);
+ if (!SafeToReadNBytes(size - position, 1, val))
+ return false;
+
+ position += 1u + val;
+ break;
+
+ case 0x00: // ?
+ case 0x01: // Boolean
+ case 0x02: // Integer
+ case 0x03: // Bit String
+ case 0x04: // Octet String
+ case 0x0A: // enumerated
+ case 0x0C: // UTF8string
+ case 0x13: // printable string
+ case 0x14: // T61 string
+ case 0x16: // IA5String
+ case 0x17: // UTC time
+ case 0x18: // Generalized time
+ case 0x1E: // BMPstring
+ ++position;
+ if (!ParseDERSize(
+ IntPtr.Add(pbSignature, (int)position),
+ size - position,
+ ref sizeFound,
+ ref bytesParsed))
+ {
+ return false;
+ }
+
+ position += bytesParsed;
+ if (!SafeToReadNBytes(size - position, 0, sizeFound))
+ return false;
+
+ if (typeSearch == iType)
+ {
+ positionFound = position;
+ lengthFound = sizeFound;
+
+ return true;
+ }
+
+ position += sizeFound;
+ break;
+
+ case 0x20: // context specific
+ case 0x21: // context specific
+ case 0x23: // context specific
+ case 0x24: // context specific
+ case 0x30: // sequence
+ case 0x31: // set
+ position++;
+ if (!ParseDERSize(
+ IntPtr.Add(pbSignature, (int)position),
+ size - position,
+ ref sizeFound,
+ ref bytesParsed))
+ {
+ return false;
+ }
+
+ position += bytesParsed;
+ break;
+
+ case 0x22: // ?
+ position += 2;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ private static bool GetGeneralizedNameAndTimeStamp(
+ IntPtr pSignerInfo,
+ SignCounterSign counter)
+ {
+ uint positionFound = 0;
+ uint lengthFound = 0;
+ var res = TryGetUnauthAttr(pSignerInfo, szOID_RFC3161_counterSign, out var attr);
+ if (!res)
+ return false;
+
+ var rgValue = Marshal.PtrToStructure(attr.rgValue);
+ var result = ParseDERFindType(
+ 0x04,
+ rgValue.pbData,
+ rgValue.cbData,
+ ref positionFound,
+ ref lengthFound);
+ if (!result)
+ return false;
+
+ // Counter Signer Timstamp
+ var pbOctetString = IntPtr.Add(rgValue.pbData, (int)positionFound);
+ (counter.TimeStamp, var timestampLength) = GetTimeStampFromDER(pbOctetString, lengthFound, ref positionFound);
+
+ // Counter Signer Name
+ var pbSignerName = IntPtr.Add(pbOctetString, (int)(positionFound + timestampLength));
+ lengthFound -= positionFound + timestampLength;
+ counter.SignerName = GetNameFromDER(pbSignerName, lengthFound);
+
+ return true;
+ }
+
+ private static (string, uint) GetTimeStampFromDER(IntPtr pbOctetString, uint lengthFound, ref uint positionFound)
+ {
+ var result = ParseDERFindType(
+ 0x18,
+ pbOctetString,
+ lengthFound,
+ ref positionFound,
+ ref lengthFound
+ );
+ if (!result)
+ return (string.Empty, 0);
+
+ var st = new SYSTEMTIME();
+ var buffer = Marshal.PtrToStringUTF8(
+ IntPtr.Add(pbOctetString, (int)positionFound),
+ (int)lengthFound
+ ) + (char)0;
+
+ short.TryParse(buffer.AsSpan(0, 4), out st.Year);
+ short.TryParse(buffer.AsSpan(4, 2), out st.Month);
+ short.TryParse(buffer.AsSpan(6, 2), out st.Day);
+ short.TryParse(buffer.AsSpan(8, 2), out st.Hour);
+ short.TryParse(buffer.AsSpan(10, 2), out st.Minute);
+ short.TryParse(buffer.AsSpan(12, 2), out st.Second);
+ short.TryParse(buffer.AsSpan(15, 3), out st.Milliseconds);
+
+ var sst = Marshal.AllocHGlobal(Marshal.SizeOf());
+ var lst = Marshal.AllocHGlobal(Marshal.SizeOf());
+ var fft = Marshal.AllocHGlobal(Marshal.SizeOf());
+ var lft = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(st, sst, true);
+ SystemTimeToFileTime(sst, fft);
+ FileTimeToLocalFileTime(fft, lft);
+ FileTimeToSystemTime(lft, lst);
+ var timestamp = TimeToString(IntPtr.Zero, lst);
+
+ Marshal.FreeHGlobal(fft);
+ Marshal.FreeHGlobal(lft);
+ Marshal.FreeHGlobal(sst);
+ Marshal.FreeHGlobal(lst);
+
+ return (timestamp, lengthFound);
+ }
+
+ private static string GetNameFromDER(IntPtr pbSignerName, uint lengthFound)
+ {
+ uint namePositionFound = 0;
+ uint nameLengthFound = 0;
+
+ while (lengthFound > 0)
+ {
+ pbSignerName = IntPtr.Add(pbSignerName, (int)(namePositionFound + nameLengthFound));
+ ParseDERFindType(
+ 0x13,
+ pbSignerName,
+ lengthFound,
+ ref namePositionFound,
+ ref nameLengthFound
+ );
+ lengthFound -= namePositionFound + nameLengthFound;
+ }
+
+ return Marshal.PtrToStringAnsi(
+ IntPtr.Add(pbSignerName, (int)namePositionFound),
+ (int)nameLengthFound
+ );
+ }
+
+ private static bool GetStringFromCertContext(IntPtr pCertContext, uint dwType, uint flag, CertNodeInfoItem info)
+ {
+ var data = CertGetNameStringA(pCertContext, dwType, flag, IntPtr.Zero, IntPtr.Zero, 0);
+ if (data == 0)
+ {
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ var pszTempName = Marshal.AllocHGlobal((int)data * sizeof(byte));
+ if (pszTempName == IntPtr.Zero)
+ {
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ data = CertGetNameStringA(pCertContext, dwType, flag, IntPtr.Zero, pszTempName, data);
+ if (data == 0)
+ {
+ Marshal.FreeHGlobal(pszTempName);
+ return false;
+ }
+
+ if (flag == 0)
+ info.IssuedTo = StripString(Marshal.PtrToStringUTF8(pszTempName));
+ else
+ info.IssuedBy = StripString(Marshal.PtrToStringUTF8(pszTempName));
+
+ Marshal.FreeHGlobal(pszTempName);
+
+ return true;
+ }
+
+ private static bool CalculateHashOfBytes(IntPtr pbBinary, uint algId, uint binary, CertNodeInfoItem info)
+ {
+ uint cbHash;
+ string algorithmName;
+ IntPtr hAlg = IntPtr.Zero;
+ IntPtr hHash = IntPtr.Zero;
+ IntPtr rgbHash = IntPtr.Zero;
+ var hexByte = new char[3];
+ var rgbDigits = "0123456789abcdef";
+ StringBuilder calcHash = new();
+
+ if (algId == CALG_SHA1)
+ {
+ algorithmName = "SHA1";
+ cbHash = SHA1LEN;
+ }
+ else if (algId == CALG_MD5)
+ {
+ algorithmName = "MD5";
+ cbHash = MD5_LEN;
+ }
+ else
+ {
+ return false;
+ }
+
+ try
+ {
+ var errorCode = BCryptOpenAlgorithmProvider(
+ out hAlg,
+ algorithmName,
+ null,
+ 0
+ );
+ if (errorCode != 0)
+ return false;
+
+ errorCode = BCryptCreateHash(
+ hAlg,
+ out hHash,
+ IntPtr.Zero,
+ 0,
+ IntPtr.Zero,
+ 0,
+ 0
+ );
+ if (errorCode != 0)
+ return false;
+
+ errorCode = BCryptHashData(
+ hHash,
+ pbBinary,
+ binary,
+ 0
+ );
+ if (errorCode != 0)
+ return false;
+
+ rgbHash = Marshal.AllocHGlobal((int)cbHash);
+ errorCode = BCryptFinishHash(
+ hHash,
+ rgbHash,
+ cbHash,
+ 0
+ );
+ if (errorCode != 0)
+ return false;
+
+ hexByte[2] = '\0';
+ for (var i = 0; i < cbHash; i++)
+ {
+ var val = Marshal.ReadByte(rgbHash, i);
+ hexByte[0] = rgbDigits[val >> 4];
+ hexByte[1] = rgbDigits[val & 0xf];
+ calcHash.Append(hexByte);
+ }
+
+ info.Thumbprint = calcHash.ToString();
+ return true;
+ }
+ finally
+ {
+ if (hHash != IntPtr.Zero)
+ BCryptDestroyHash(hHash);
+
+ if (hAlg != IntPtr.Zero)
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+
+ if (rgbHash != IntPtr.Zero)
+ Marshal.FreeHGlobal(rgbHash);
+ }
+ }
+
+ private static bool TryGetUnauthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
+ {
+ int n = 0;
+ var signerInfo = Marshal.PtrToStructure(pSignerInfo);
+ attr = new CRYPT_ATTRIBUTE();
+ for (; n < signerInfo.UnauthAttrs.cbData; n++)
+ {
+ attr = Marshal.PtrToStructure(
+ IntPtr.Add(signerInfo.UnauthAttrs.pbData, n * Marshal.SizeOf())
+ );
+ if (attr.pszObjId == oid)
+ break;
+ }
+
+ return n < signerInfo.UnauthAttrs.cbData;
+ }
+
+ private static bool TryGetAuthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
+ {
+ int n = 0;
+ var signerInfo = Marshal.PtrToStructure(pSignerInfo);
+ attr = new CRYPT_ATTRIBUTE();
+ for (; n < signerInfo.AuthAttrs.cbData; n++)
+ {
+ attr = Marshal.PtrToStructure(
+ IntPtr.Add(signerInfo.AuthAttrs.pbData, n * Marshal.SizeOf())
+ );
+ if (attr.pszObjId == oid)
+ break;
+ }
+
+ return n < signerInfo.AuthAttrs.cbData;
+ }
+
+ private static bool GetNestedSignerInfo(ref SignDataHandle AuthSignData, List NestedChain)
+ {
+ var succeded = false;
+ var hNestedMsg = IntPtr.Zero;
+ if (AuthSignData.pSignerInfo == IntPtr.Zero)
+ return false;
+
+ try
+ {
+ var res = TryGetUnauthAttr(AuthSignData.pSignerInfo, szOID_NESTED_SIGNATURE, out var attr);
+ if (!res)
+ return false;
+
+ var rgValue = Marshal.PtrToStructure(attr.rgValue);
+ var cbCurrData = rgValue.cbData;
+ var pbCurrData = rgValue.pbData;
+
+ var upperBound = IntPtr.Add(AuthSignData.pSignerInfo, (int)AuthSignData.dwObjSize);
+ while (pbCurrData > AuthSignData.pSignerInfo && pbCurrData < upperBound)
+ {
+ var nestedHandle = new SignDataHandle() { dwObjSize = 0 };
+ if (!Memcmp(pbCurrData, SG_ProtoCoded) ||
+ !Memcmp(IntPtr.Add(pbCurrData, 6), SG_SignedData))
+ {
+ break;
+ }
+
+ hNestedMsg = CryptMsgOpenToDecode(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ 0,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ IntPtr.Zero
+ );
+ if (hNestedMsg == IntPtr.Zero)
+ return false;
+
+ cbCurrData = XCHWordLitend(unchecked((ushort)Marshal.ReadInt16(pbCurrData)) + 2u) + 4u;
+ var pbNextData = pbCurrData;
+ pbNextData = IntPtr.Add(pbNextData, (int)EightByteAlign(cbCurrData, unchecked(pbCurrData)));
+ var result = CryptMsgUpdate(hNestedMsg, pbCurrData, cbCurrData, true);
+ pbCurrData = pbNextData;
+ if (!result)
+ continue;
+
+ result = CustomCryptMsgGetParam(
+ hNestedMsg,
+ CMSG_SIGNER_INFO_PARAM,
+ 0,
+ ref nestedHandle.pSignerInfo,
+ ref nestedHandle.dwObjSize
+ );
+ if (!result)
+ continue;
+
+ nestedHandle.hCertStoreHandle = CertOpenStore(
+ CERT_STORE_PROV_MSG,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ IntPtr.Zero,
+ 0,
+ hNestedMsg
+ );
+
+ succeded = true;
+ NestedChain.Add(nestedHandle);
+ }
+ }
+ finally
+ {
+ if (hNestedMsg != IntPtr.Zero)
+ CryptMsgClose(hNestedMsg);
+ }
+
+ return succeded;
+ }
+ private static bool CustomCryptMsgGetParam(
+ IntPtr hCryptMsg,
+ uint paramType,
+ uint index,
+ ref IntPtr pParam,
+ ref uint outSize)
+ {
+ bool result;
+ uint size = 0;
+
+ result = CryptMsgGetParam(
+ hCryptMsg,
+ paramType,
+ index,
+ IntPtr.Zero,
+ ref size
+ );
+ if (!result)
+ return false;
+
+ pParam = Marshal.AllocHGlobal((int)size);
+ if (pParam == IntPtr.Zero)
+ return false;
+
+ result = CryptMsgGetParam(
+ hCryptMsg,
+ paramType,
+ index,
+ pParam,
+ ref size
+ );
+ if (!result)
+ return false;
+
+ outSize = size;
+ return true;
+ }
+
+ private static ushort XCHWordLitend(uint num)
+ => (ushort)(((((ushort)num) & 0xFF00) >> 8) | (((ushort)num) & 0x00FF) << 8);
+
+ private static long EightByteAlign(long offset, long b)
+ => ((offset + b + 7) & 0xFFFFFFF8L) - (b & 0xFFFFFFF8L);
+
+ private static bool Memcmp(IntPtr ptr1, byte[] arr)
+ {
+ for (var i = 0; i < arr.Length; i++)
+ {
+ if (Marshal.ReadByte(ptr1, i) != arr[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ private static (bool, string) CalculateSignVersion(uint versionNumber)
+ {
+ var res = versionNumber switch
+ {
+ CERT_V1 => "V1",
+ CERT_V2 => "V2",
+ CERT_V3 => "V3",
+ _ => "Unknown",
+ };
+ return (true, res);
+ }
+
+ private static bool CalculateDigestAlgorithm(string pszObjId, SignNodeInfo info)
+ {
+ if (string.IsNullOrWhiteSpace(pszObjId))
+ info.DigestAlgorithm = "Unknown";
+ else if (pszObjId == szOID_OIWSEC_sha1)
+ info.DigestAlgorithm = "SHA1";
+ else if (pszObjId == szOID_RSA_MD5)
+ info.DigestAlgorithm = "MD5";
+ else if (pszObjId == szOID_NIST_sha256)
+ info.DigestAlgorithm = "SHA256";
+ else
+ info.DigestAlgorithm = StripString(pszObjId);
+
+ return true;
+ }
+
+ private static bool CalculateCertAlgorithm(string pszObjId, CertNodeInfoItem info)
+ {
+ if (string.IsNullOrWhiteSpace(pszObjId))
+ info.SignAlgorithm = "Unknown";
+ else if (pszObjId == szOID_RSA_SHA1RSA)
+ info.SignAlgorithm = "sha1RSA(RSA)";
+ else if (pszObjId == szOID_OIWSEC_sha1RSASign)
+ info.SignAlgorithm = "sha1RSA(OIW)";
+ else if (pszObjId == szOID_RSA_MD5RSA)
+ info.SignAlgorithm = "md5RSA(RSA)";
+ else if (pszObjId == szOID_OIWSEC_md5RSA)
+ info.SignAlgorithm = "md5RSA(OIW)";
+ else if (pszObjId == szOID_RSA_MD2RSA)
+ info.SignAlgorithm = "md2RSA(RSA)";
+ else if (pszObjId == szOID_RSA_SHA256RSA)
+ info.SignAlgorithm = "sha256RSA(RSA)";
+ else
+ info.SignAlgorithm = StripString(pszObjId);
+
+ return true;
+ }
+
+ private static bool SafeToReadNBytes(uint size, uint start, uint requestSize)
+ => size - start >= requestSize;
+
+ private static void ParseDERType(byte bIn, ref int iType, ref int iClass)
+ {
+ iType = bIn & 0x3F;
+ iClass = bIn >> 6;
+ }
+
+ private static uint ReadNumberFromNBytes(IntPtr pbSignature, uint start, uint requestSize)
+ {
+ uint number = 0;
+ for (var i = 0; i < requestSize; i++)
+ number = number * 0x100 + Marshal.ReadByte(pbSignature, (int)(start + i));
+
+ return number;
+ }
+
+ private static bool ParseDERSize(IntPtr pbSignature, uint size, ref uint sizeFound, ref uint bytesParsed)
+ {
+ var val = Marshal.ReadByte(pbSignature);
+ if (val > 0x80 && !SafeToReadNBytes(size, 1, val - 0x80u))
+ return false;
+
+ if (val <= 0x80)
+ {
+ sizeFound = val;
+ bytesParsed = 1;
+ }
+ else
+ {
+ sizeFound = ReadNumberFromNBytes(pbSignature, 1, val - 0x80u);
+ bytesParsed = val - 0x80u + 1;
+ }
+
+ return true;
+ }
+
+ private static string StripString(string? str)
+ {
+ return str?
+ .Replace("\t", "")?
+ .Replace("\n", "")?
+ .Replace("\r", "")?
+ .Replace(((char)0).ToString(), "") ?? string.Empty;
+ }
+
+ private static string TimeToString(IntPtr pftIn, IntPtr pstIn = 0)
+ {
+ if (pstIn == IntPtr.Zero)
+ {
+ if (pftIn == IntPtr.Zero)
+ return string.Empty;
+
+ pstIn = Marshal.AllocHGlobal(Marshal.SizeOf());
+ FileTimeToSystemTime(pftIn, pstIn);
+ }
+
+ var st = Marshal.PtrToStructure(pstIn);
+ var date = new DateTime(
+ st.Year, st.Month, st.Day,
+ st.Hour, st.Minute, st.Second
+ );
+
+ return formatter.ToLongLabel(date);
+ }
+
+ class SignCounterSign
+ {
+ public string SignerName { get; set; } = string.Empty;
+ public string TimeStamp { get; set; } = string.Empty;
+ }
+
+ class SignNodeInfo
+ {
+ public bool IsValid { get; set; } = false;
+ public string DigestAlgorithm { get; set; } = string.Empty;
+ public string Version { get; set; } = string.Empty;
+ public SignCounterSign CounterSign { get; set; } = new();
+ public List CertChain = new();
}
}
}
diff --git a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
index 7b83c4c0e90c..65d0554c1c31 100644
--- a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
@@ -16,8 +16,7 @@ public SignaturesViewModel(ListedItem item)
_cancellationTokenSource = new();
Signatures = new();
- var signatures = DigitalSignaturesUtil.GetSignaturesOfItem(item.ItemPath);
- signatures.ForEach(s => Signatures.Add(s));
+ DigitalSignaturesUtil.LoadItemSignatures(item.ItemPath, Signatures);
}
public void Dispose()
diff --git a/src/Files.App/Views/Properties/SignaturesPage.xaml b/src/Files.App/Views/Properties/SignaturesPage.xaml
index edeec6562dcd..9f507ea38c9b 100644
--- a/src/Files.App/Views/Properties/SignaturesPage.xaml
+++ b/src/Files.App/Views/Properties/SignaturesPage.xaml
@@ -26,15 +26,17 @@
-
+
+
+
-
-
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
-
+
-
-
-
-
-
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
-
-
-
+
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
From 03eb52237b1c3c1a310bf1bb6a23b68a0c587a59 Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Sun, 27 Jul 2025 22:25:54 +0200
Subject: [PATCH 03/10] Support "Details" button & Cleanup
---
src/Files.App/Data/Items/CertNodeInfoItem.cs | 6 -
.../Data/Models/SignatureInfoItem.cs | 13 +-
.../Helpers/Win32/Win32PInvoke.Methods.cs | 70 +--
.../Helpers/Win32/Win32PInvoke.Structs.cs | 24 +-
.../Utils/Signatures/DigitalSignaturesUtil.cs | 441 +++++++-----------
.../Properties/SignaturesViewModel.cs | 12 +-
.../Views/Properties/SignaturesPage.xaml.cs | 2 +-
7 files changed, 200 insertions(+), 368 deletions(-)
diff --git a/src/Files.App/Data/Items/CertNodeInfoItem.cs b/src/Files.App/Data/Items/CertNodeInfoItem.cs
index 1fdb3fed603f..3c5e9b131f7b 100644
--- a/src/Files.App/Data/Items/CertNodeInfoItem.cs
+++ b/src/Files.App/Data/Items/CertNodeInfoItem.cs
@@ -11,14 +11,8 @@ public class CertNodeInfoItem
public string Version { get; set; } = string.Empty;
- public string SerialNumber { get; set; } = string.Empty;
-
- public string Thumbprint { get; set; } = string.Empty;
-
public string ValidFrom { get; set; } = string.Empty;
public string ValidTo { get; set; } = string.Empty;
-
- public string SignAlgorithm { get; set; } = string.Empty;
}
}
diff --git a/src/Files.App/Data/Models/SignatureInfoItem.cs b/src/Files.App/Data/Models/SignatureInfoItem.cs
index d9bc9154a7bb..11e06cea0a15 100644
--- a/src/Files.App/Data/Models/SignatureInfoItem.cs
+++ b/src/Files.App/Data/Models/SignatureInfoItem.cs
@@ -1,12 +1,19 @@
// Copyright (c) Files Community
// Licensed under the MIT License.
+using Files.App.Utils.Signatures;
using System.Windows.Input;
namespace Files.App.Data.Models
{
public sealed partial class SignatureInfoItem : ObservableObject
{
+ private readonly string _fileName;
+
+ private readonly IntPtr _hwndParent;
+
+ private readonly int _index;
+
private string _Version = string.Empty;
public string Version
{
@@ -66,14 +73,18 @@ public bool Verified
public ICommand OpenDetailsCommand { get; }
- public SignatureInfoItem(List chain)
+ public SignatureInfoItem(string fileName, int index, IntPtr hWnd, List chain)
{
+ _fileName = fileName;
+ _hwndParent = hWnd;
+ _index = index;
SignChain = chain ?? new List();
OpenDetailsCommand = new AsyncRelayCommand(DoOpenDetails);
}
private Task DoOpenDetails()
{
+ DigitalSignaturesUtil.DisplaySignerInfoDialog(_fileName, _hwndParent, _index);
return Task.CompletedTask;
}
}
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
index e2d2c2a834b1..ae2022366db4 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
@@ -415,15 +415,6 @@ public static extern bool CryptDecodeObject(
ref uint pcbStructInfo
);
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptBinaryToStringA(
- IntPtr pbBinary,
- uint cbBinary,
- uint dwFlags,
- IntPtr pszString,
- ref uint pcchString
- );
-
[DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CertFindCertificateInStore(
IntPtr hCertStore,
@@ -462,15 +453,6 @@ public static extern bool CertCloseStore(
uint dwFlags
);
- // wintrust.dll
- [DllImport("wintrust.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptCATAdminCalcHashFromFileHandle(
- IntPtr hFile,
- ref uint pdwHash,
- IntPtr pReserved,
- uint dwFlags
- );
-
[DllImport("wintrust.dll")]
public static extern long WinVerifyTrust(
IntPtr hwnd,
@@ -478,54 +460,6 @@ public static extern long WinVerifyTrust(
IntPtr pWVTData
);
- // ncrypt.dll
- [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool BCryptDestroyHash(
- IntPtr hHash
- );
-
- [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern uint BCryptFinishHash(
- IntPtr hHash,
- IntPtr pbOutput,
- uint cbOutput,
- uint dwFlags
- );
-
- [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern uint BCryptOpenAlgorithmProvider(
- out IntPtr phAlgorithm,
- string pszAlgId,
- string pszImplementation,
- uint dwFlags
- );
-
- [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern uint BCryptCloseAlgorithmProvider(
- IntPtr hAlgorithm,
- uint dwFlags
- );
-
- [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern uint BCryptCreateHash(
- IntPtr hAlgorithm,
- out IntPtr hHash,
- IntPtr pbHashObject,
- uint cbHashObject,
- IntPtr pbSecret,
- uint cbSecret,
- uint flags
- );
-
-
- [DllImport("ncrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern uint BCryptHashData(
- IntPtr hHash,
- IntPtr pbInput,
- uint cbInput,
- uint dwFlags
- );
-
// kernel32.dll
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool FileTimeToSystemTime(
@@ -544,5 +478,9 @@ public static extern bool SystemTimeToFileTime(
IntPtr lpSystemTime,
IntPtr lpFileTime
);
+
+ // cryptui.dll
+ [DllImport("cryptui.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool CryptUIDlgViewSignerInfo(IntPtr pViewInfo);
}
}
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
index 7ed7f1305488..414eb64ec9a6 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
@@ -257,13 +257,6 @@ public struct CERT_ALT_NAME_INFO
public IntPtr rgAltEntry;
}
- [StructLayout(LayoutKind.Sequential)]
- public struct CRL_DIST_POINT_NAME
- {
- public uint dwDistPointNameChoice;
- public CERT_ALT_NAME_INFO FullName;
- }
-
[StructLayout(LayoutKind.Sequential)]
public struct CERT_CONTEXT
{
@@ -343,5 +336,22 @@ public struct WINTRUST_DATA
public uint dwUIContext;
public IntPtr pSignatureSettings;
}
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct CRYPTUI_VIEWSIGNERINFO_STRUCT
+ {
+ public uint dwSize;
+ public IntPtr hwndParent;
+ public uint dwFlags;
+ public IntPtr szTitle;
+ public IntPtr pSignerInfo;
+ public IntPtr hMsg;
+ public IntPtr pszOID;
+ public uint? dwReserved;
+ public uint cStores;
+ public IntPtr rghStores;
+ public uint cPropPages;
+ public IntPtr rgPropPages;
+ }
}
}
diff --git a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
index fbb2b2825cf9..347dab0fa8bd 100644
--- a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
+++ b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
@@ -2,21 +2,13 @@
// Licensed under the MIT License.
using System.Runtime.InteropServices;
-using System.Text;
using static Files.App.Helpers.Win32PInvoke;
namespace Files.App.Utils.Signatures
{
public static class DigitalSignaturesUtil
{
- // Constants
- private const int SHA1LEN = 20;
- private const int MD5_LEN = 16;
-
- private const uint CALG_SHA1 = 0x00008004;
- private const uint CALG_MD5 = 0x00008003;
-
- // - OIDs
+ // OIDs
private const string szOID_NESTED_SIGNATURE = "1.3.6.1.4.1.311.2.4.1";
private const string szOID_RSA_counterSign = "1.2.840.113549.1.9.6";
private const string szOID_RSA_signingTime = "1.2.840.113549.1.9.5";
@@ -24,15 +16,8 @@ public static class DigitalSignaturesUtil
private const string szOID_OIWSEC_sha1 = "1.3.14.3.2.26";
private const string szOID_RSA_MD5 = "1.2.840.113549.2.5";
private const string szOID_NIST_sha256 = "2.16.840.1.101.3.4.2.1";
- private const string szOID_RSA_SHA1RSA = "1.2.840.113549.1.1.5";
- private const string szOID_OIWSEC_sha1RSASign = "1.3.14.3.2.29";
- private const string szOID_RSA_MD5RSA = "1.2.840.113549.1.1.4";
- private const string szOID_OIWSEC_md5RSA = "1.3.14.3.2.3";
- private const string szOID_RSA_MD2RSA = "1.2.840.113549.1.1.2";
- private const string szOID_RSA_SHA256RSA = "1.2.840.113549.1.1.11";
-
- // - Flags
- private const uint CRYPT_STRING_HEX = 0x00000004;
+
+ // Flags
private const uint CERT_NAME_SIMPLE_DISPLAY_TYPE = 4;
private const uint CERT_FIND_SUBJECT_NAME = 131079;
private const uint CERT_FIND_ISSUER_NAME = 131076;
@@ -51,7 +36,7 @@ public static class DigitalSignaturesUtil
private const uint CMSG_SIGNER_INFO_PARAM = 6;
- // - Version numbers
+ // Version numbers
private const uint CERT_V1 = 0;
private const uint CERT_V2 = 1;
private const uint CERT_V3 = 2;
@@ -66,17 +51,21 @@ public static class DigitalSignaturesUtil
private static readonly IDateTimeFormatter formatter = Ioc.Default.GetRequiredService();
- public static void LoadItemSignatures(string filePath, ObservableCollection signatures)
+ public static void LoadItemSignatures(
+ string filePath,
+ ObservableCollection signatures,
+ IntPtr hWnd,
+ CancellationToken ct)
{
var signChain = new List();
- GetSignerCertificateInfo(filePath, signChain);
+ GetSignerCertificateInfo(filePath, signChain, ct);
foreach (var signNode in signChain)
{
if (signNode.CertChain.Count == 0)
continue;
- var signatureInfo = new SignatureInfoItem(signNode.CertChain)
+ var signatureInfo = new SignatureInfoItem(filePath, signNode.Index, hWnd, signNode.CertChain)
{
Version = signNode.Version,
IssuedBy = signNode.CertChain[0].IssuedBy,
@@ -90,51 +79,88 @@ public static void LoadItemSignatures(string filePath, ObservableCollection();
try
{
- for (var i = 0; i < cbData && i < 0x400; i++)
- {
- Marshal.WriteByte(
- abSerial,
- i,
- Marshal.ReadByte(pbData, (int)(cbData - 1 - i))
- );
- }
+ var result = TryGetSignerInfo(
+ filePath,
+ ref hAuthCryptMsg,
+ ref signHandle.hCertStoreHandle,
+ ref signHandle.pSignerInfo,
+ ref signHandle.dwObjSize
+ );
+ if (!result || signHandle.pSignerInfo == IntPtr.Zero)
+ return;
- var result = CryptBinaryToStringA(abSerial, cbData, CRYPT_STRING_HEX, IntPtr.Zero, ref size);
- if (!result)
- return false;
+ signDataChain.Add(signHandle);
+ GetNestedSignerInfo(ref signHandle, signDataChain);
+ if (index >= signDataChain.Count)
+ return;
- nameBuff = Marshal.AllocHGlobal(0x400);
- result = CryptBinaryToStringA(abSerial, cbData, CRYPT_STRING_HEX, nameBuff, ref size);
- if (!result)
- return false;
+ signHandle = signDataChain[index];
+ var signerInfo = Marshal.PtrToStructure(signHandle.pSignerInfo);
+ var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(signerInfo.Issuer, pIssuer, false);
+ var pCertContext = CertFindCertificateInStore(
+ signHandle.hCertStoreHandle,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ CERT_FIND_ISSUER_NAME,
+ pIssuer,
+ IntPtr.Zero
+ );
+ Marshal.FreeHGlobal(pIssuer);
+ if (pCertContext == IntPtr.Zero)
+ return;
- StringBuilder builder = new(Marshal.PtrToStringAnsi(nameBuff));
- var iter2 = 0;
- for (var iter1 = 0; iter1 < size; iter1++)
+ var viewInfo = new CRYPTUI_VIEWSIGNERINFO_STRUCT
{
- if (!char.IsWhiteSpace(builder[iter1]))
- builder[iter2++] = builder[iter1];
- }
+ dwSize = (uint)Marshal.SizeOf(),
+ hwndParent = hwndParent,
+ dwFlags = 0,
+ szTitle = IntPtr.Zero,
+ pSignerInfo = signHandle.pSignerInfo,
+ hMsg = hAuthCryptMsg,
+ pszOID = IntPtr.Zero,
+ dwReserved = null,
+ cStores = 1,
+ rghStores = Marshal.AllocHGlobal(IntPtr.Size),
+ cPropPages = 0,
+ rgPropPages = IntPtr.Zero
+ };
+ Marshal.WriteIntPtr(viewInfo.rghStores, signHandle.hCertStoreHandle);
+ var pViewInfo = Marshal.AllocHGlobal((int)viewInfo.dwSize);
+ Marshal.StructureToPtr(viewInfo, pViewInfo, false);
- builder.Remove(iter2, builder.Length - iter2);
- info.SerialNumber = StripString(builder.ToString());
+ result = CryptUIDlgViewSignerInfo(pViewInfo);
- return true;
+ Marshal.FreeHGlobal(viewInfo.rghStores);
+ Marshal.FreeHGlobal(pViewInfo);
+ CertFreeCertificateContext(pCertContext);
}
finally
{
- Marshal.FreeHGlobal(abSerial);
- if (nameBuff != IntPtr.Zero)
- Marshal.FreeHGlobal(nameBuff);
+ // Since signDataChain contains nested signatures,
+ // you must release them starting from the last one.
+ for (int i = signDataChain.Count - 1; i >= 0; i--)
+ {
+ if (signDataChain[i].pSignerInfo != IntPtr.Zero)
+ Marshal.FreeHGlobal(signDataChain[i].pSignerInfo);
+
+ if (signDataChain[i].hCertStoreHandle != IntPtr.Zero)
+ CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
+ }
+
+ if (hAuthCryptMsg != IntPtr.Zero)
+ CryptMsgClose(hAuthCryptMsg);
}
}
@@ -149,19 +175,10 @@ private static bool GetSignerSignatureInfo(
var pCertInfo = currContext.pCertInfo;
var certNode = new CertNodeInfoItem();
var certInfo = Marshal.PtrToStructure(pCertInfo);
- var szObjId = certInfo.SignatureAlgorithm.pszObjId;
- CalculateCertAlgorithm(szObjId, certNode);
- CalculateSignSerial(certInfo.SerialNumber.pbData, certInfo.SerialNumber.cbData, certNode);
(_, certNode.Version) = CalculateSignVersion(certInfo.dwVersion);
GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, certNode);
GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 1, certNode);
- CalculateHashOfBytes(
- currContext.pbCertEncoded,
- CALG_SHA1,
- currContext.cbCertEncoded,
- certNode
- );
var pft = Marshal.AllocHGlobal(Marshal.SizeOf());
Marshal.StructureToPtr(certInfo.NotBefore, pft, false);
@@ -219,7 +236,7 @@ private static bool GetSignerSignatureInfo(
return !result;
}
- private static bool GetSignerCertificateInfo(string fileName, List signChain)
+ private static bool GetSignerCertificateInfo(string fileName, List signChain, CancellationToken ct)
{
var succeded = false;
var authSignData = new SignDataHandle();
@@ -239,45 +256,26 @@ private static bool GetSignerCertificateInfo(string fileName, List
return false;
var hAuthCryptMsg = IntPtr.Zero;
- uint encoding = 0;
- var pDummy = IntPtr.Zero;
- uint dummy = 0;
- var pFileName = Marshal.StringToHGlobalAuto(fileName);
- var result = CryptQueryObject(
- CERT_QUERY_OBJECT_FILE,
- pFileName,
- CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
- CERT_QUERY_FORMAT_FLAG_BINARY,
- 0,
- ref encoding,
- ref dummy,
- ref dummy,
- ref authSignData.hCertStoreHandle,
+ var result = TryGetSignerInfo(
+ fileName,
ref hAuthCryptMsg,
- ref pDummy
+ ref authSignData.hCertStoreHandle,
+ ref authSignData.pSignerInfo,
+ ref authSignData.dwObjSize
);
- Marshal.FreeHGlobal(pFileName);
- if (!result)
+ if (hAuthCryptMsg != IntPtr.Zero)
{
- CertCloseStore(hSystemStore, 0);
- return false;
+ CryptMsgClose(hAuthCryptMsg);
+ hAuthCryptMsg = IntPtr.Zero;
}
- result = CustomCryptMsgGetParam(
- hAuthCryptMsg,
- CMSG_SIGNER_INFO_PARAM,
- 0,
- ref authSignData.pSignerInfo,
- ref authSignData.dwObjSize
- );
- CryptMsgClose(hAuthCryptMsg);
- hAuthCryptMsg = IntPtr.Zero;
if (!result)
{
- CertCloseStore(authSignData.hCertStoreHandle, 0);
- CertCloseStore(hSystemStore, 0);
+ if (authSignData.hCertStoreHandle != IntPtr.Zero)
+ CertCloseStore(authSignData.hCertStoreHandle, 0);
+ CertCloseStore(hSystemStore, 0);
return false;
}
@@ -286,6 +284,12 @@ ref authSignData.dwObjSize
for (var i = 0; i < signDataChain.Count; i++)
{
+ if (ct.IsCancellationRequested)
+ {
+ CertCloseStore(hSystemStore, 0);
+ return false;
+ }
+
var pCurrContext = IntPtr.Zero;
var pCounterSigner = IntPtr.Zero;
var signNode = new SignNodeInfo();
@@ -294,7 +298,7 @@ ref authSignData.dwObjSize
if (pCounterSigner != IntPtr.Zero)
GetCounterSignerData(pCounterSigner, signNode.CounterSign);
else
- GetGeneralizedNameAndTimeStamp(signDataChain[i].pSignerInfo, signNode.CounterSign);
+ GetGeneralizedTimeStamp(signDataChain[i].pSignerInfo, signNode.CounterSign);
var signerInfo = Marshal.PtrToStructure(signDataChain[i].pSignerInfo);
var szObjId = signerInfo.HashAlgorithm.pszObjId;
@@ -341,6 +345,7 @@ ref authSignData.dwObjSize
succeded = true;
signNode.IsValid = VerifyySignature(fileName);
+ signNode.Index = i;
signChain.Add(signNode);
}
@@ -348,34 +353,6 @@ ref authSignData.dwObjSize
return succeded;
}
- private static bool CustomCryptCalcFileHash(
- IntPtr fileHandle,
- ref IntPtr szBuffer,
- ref uint hashSize)
- {
- hashSize = 0;
- CryptCATAdminCalcHashFromFileHandle(
- fileHandle,
- ref hashSize,
- IntPtr.Zero,
- 0
- );
- if (hashSize == 0)
- return false;
-
- szBuffer = Marshal.AllocHGlobal((int)hashSize * sizeof(byte));
- var result = CryptCATAdminCalcHashFromFileHandle(
- fileHandle,
- ref hashSize,
- szBuffer,
- 0
- );
- if (!result)
- Marshal.FreeHGlobal(szBuffer);
-
- return result;
- }
-
private static bool VerifyySignature(string certPath)
{
var actionGuid = new Guid("{00AAC56B-CD44-11D0-8CC2-00C04FC295EE}");
@@ -433,11 +410,50 @@ private static bool VerifyySignature(string certPath)
}
}
+ private static bool TryGetSignerInfo(
+ string fileName,
+ ref IntPtr hMsg,
+ ref IntPtr hCertStore,
+ ref IntPtr pSignerInfo,
+ ref uint signerSize,
+ uint index = 0)
+ {
+ uint encoding = 0;
+ var pDummy = IntPtr.Zero;
+ uint dummy = 0;
+ var pFileName = Marshal.StringToHGlobalAuto(fileName);
+ var result = CryptQueryObject(
+ CERT_QUERY_OBJECT_FILE,
+ pFileName,
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+ CERT_QUERY_FORMAT_FLAG_BINARY,
+ 0,
+ ref encoding,
+ ref dummy,
+ ref dummy,
+ ref hCertStore,
+ ref hMsg,
+ ref pDummy
+ );
+ Marshal.FreeHGlobal(pFileName);
+
+ if (!result)
+ return false;
+
+ result = CustomCryptMsgGetParam(
+ hMsg,
+ CMSG_SIGNER_INFO_PARAM,
+ index,
+ ref pSignerInfo,
+ ref signerSize
+ );
+
+ return result;
+ }
+
private static bool GetCounterSignerInfo(IntPtr pSignerInfo, ref IntPtr pTargetSigner)
{
uint objSize = 0;
- int n;
-
if (pSignerInfo == IntPtr.Zero)
return false;
@@ -642,7 +658,7 @@ private static bool ParseDERFindType(
return false;
}
- private static bool GetGeneralizedNameAndTimeStamp(
+ private static bool GetGeneralizedTimeStamp(
IntPtr pSignerInfo,
SignCounterSign counter)
{
@@ -664,17 +680,12 @@ private static bool GetGeneralizedNameAndTimeStamp(
// Counter Signer Timstamp
var pbOctetString = IntPtr.Add(rgValue.pbData, (int)positionFound);
- (counter.TimeStamp, var timestampLength) = GetTimeStampFromDER(pbOctetString, lengthFound, ref positionFound);
-
- // Counter Signer Name
- var pbSignerName = IntPtr.Add(pbOctetString, (int)(positionFound + timestampLength));
- lengthFound -= positionFound + timestampLength;
- counter.SignerName = GetNameFromDER(pbSignerName, lengthFound);
-
+ counter.TimeStamp = GetTimeStampFromDER(pbOctetString, lengthFound, ref positionFound);
+
return true;
}
- private static (string, uint) GetTimeStampFromDER(IntPtr pbOctetString, uint lengthFound, ref uint positionFound)
+ private static string GetTimeStampFromDER(IntPtr pbOctetString, uint lengthFound, ref uint positionFound)
{
var result = ParseDERFindType(
0x18,
@@ -684,7 +695,7 @@ private static (string, uint) GetTimeStampFromDER(IntPtr pbOctetString, uint len
ref lengthFound
);
if (!result)
- return (string.Empty, 0);
+ return string.Empty;
var st = new SYSTEMTIME();
var buffer = Marshal.PtrToStringUTF8(
@@ -692,13 +703,13 @@ ref lengthFound
(int)lengthFound
) + (char)0;
- short.TryParse(buffer.AsSpan(0, 4), out st.Year);
- short.TryParse(buffer.AsSpan(4, 2), out st.Month);
- short.TryParse(buffer.AsSpan(6, 2), out st.Day);
- short.TryParse(buffer.AsSpan(8, 2), out st.Hour);
- short.TryParse(buffer.AsSpan(10, 2), out st.Minute);
- short.TryParse(buffer.AsSpan(12, 2), out st.Second);
- short.TryParse(buffer.AsSpan(15, 3), out st.Milliseconds);
+ _ = short.TryParse(buffer.AsSpan(0, 4), out st.Year);
+ _ = short.TryParse(buffer.AsSpan(4, 2), out st.Month);
+ _ = short.TryParse(buffer.AsSpan(6, 2), out st.Day);
+ _ = short.TryParse(buffer.AsSpan(8, 2), out st.Hour);
+ _ = short.TryParse(buffer.AsSpan(10, 2), out st.Minute);
+ _ = short.TryParse(buffer.AsSpan(12, 2), out st.Second);
+ _ = short.TryParse(buffer.AsSpan(15, 3), out st.Milliseconds);
var sst = Marshal.AllocHGlobal(Marshal.SizeOf());
var lst = Marshal.AllocHGlobal(Marshal.SizeOf());
@@ -715,31 +726,7 @@ ref lengthFound
Marshal.FreeHGlobal(sst);
Marshal.FreeHGlobal(lst);
- return (timestamp, lengthFound);
- }
-
- private static string GetNameFromDER(IntPtr pbSignerName, uint lengthFound)
- {
- uint namePositionFound = 0;
- uint nameLengthFound = 0;
-
- while (lengthFound > 0)
- {
- pbSignerName = IntPtr.Add(pbSignerName, (int)(namePositionFound + nameLengthFound));
- ParseDERFindType(
- 0x13,
- pbSignerName,
- lengthFound,
- ref namePositionFound,
- ref nameLengthFound
- );
- lengthFound -= namePositionFound + nameLengthFound;
- }
-
- return Marshal.PtrToStringAnsi(
- IntPtr.Add(pbSignerName, (int)namePositionFound),
- (int)nameLengthFound
- );
+ return timestamp;
}
private static bool GetStringFromCertContext(IntPtr pCertContext, uint dwType, uint flag, CertNodeInfoItem info)
@@ -775,99 +762,6 @@ private static bool GetStringFromCertContext(IntPtr pCertContext, uint dwType, u
return true;
}
- private static bool CalculateHashOfBytes(IntPtr pbBinary, uint algId, uint binary, CertNodeInfoItem info)
- {
- uint cbHash;
- string algorithmName;
- IntPtr hAlg = IntPtr.Zero;
- IntPtr hHash = IntPtr.Zero;
- IntPtr rgbHash = IntPtr.Zero;
- var hexByte = new char[3];
- var rgbDigits = "0123456789abcdef";
- StringBuilder calcHash = new();
-
- if (algId == CALG_SHA1)
- {
- algorithmName = "SHA1";
- cbHash = SHA1LEN;
- }
- else if (algId == CALG_MD5)
- {
- algorithmName = "MD5";
- cbHash = MD5_LEN;
- }
- else
- {
- return false;
- }
-
- try
- {
- var errorCode = BCryptOpenAlgorithmProvider(
- out hAlg,
- algorithmName,
- null,
- 0
- );
- if (errorCode != 0)
- return false;
-
- errorCode = BCryptCreateHash(
- hAlg,
- out hHash,
- IntPtr.Zero,
- 0,
- IntPtr.Zero,
- 0,
- 0
- );
- if (errorCode != 0)
- return false;
-
- errorCode = BCryptHashData(
- hHash,
- pbBinary,
- binary,
- 0
- );
- if (errorCode != 0)
- return false;
-
- rgbHash = Marshal.AllocHGlobal((int)cbHash);
- errorCode = BCryptFinishHash(
- hHash,
- rgbHash,
- cbHash,
- 0
- );
- if (errorCode != 0)
- return false;
-
- hexByte[2] = '\0';
- for (var i = 0; i < cbHash; i++)
- {
- var val = Marshal.ReadByte(rgbHash, i);
- hexByte[0] = rgbDigits[val >> 4];
- hexByte[1] = rgbDigits[val & 0xf];
- calcHash.Append(hexByte);
- }
-
- info.Thumbprint = calcHash.ToString();
- return true;
- }
- finally
- {
- if (hHash != IntPtr.Zero)
- BCryptDestroyHash(hHash);
-
- if (hAlg != IntPtr.Zero)
- BCryptCloseAlgorithmProvider(hAlg, 0);
-
- if (rgbHash != IntPtr.Zero)
- Marshal.FreeHGlobal(rgbHash);
- }
- }
-
private static bool TryGetUnauthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
{
int n = 0;
@@ -978,6 +872,7 @@ ref nestedHandle.dwObjSize
return succeded;
}
+
private static bool CustomCryptMsgGetParam(
IntPtr hCryptMsg,
uint paramType,
@@ -1061,28 +956,6 @@ private static bool CalculateDigestAlgorithm(string pszObjId, SignNodeInfo info)
return true;
}
- private static bool CalculateCertAlgorithm(string pszObjId, CertNodeInfoItem info)
- {
- if (string.IsNullOrWhiteSpace(pszObjId))
- info.SignAlgorithm = "Unknown";
- else if (pszObjId == szOID_RSA_SHA1RSA)
- info.SignAlgorithm = "sha1RSA(RSA)";
- else if (pszObjId == szOID_OIWSEC_sha1RSASign)
- info.SignAlgorithm = "sha1RSA(OIW)";
- else if (pszObjId == szOID_RSA_MD5RSA)
- info.SignAlgorithm = "md5RSA(RSA)";
- else if (pszObjId == szOID_OIWSEC_md5RSA)
- info.SignAlgorithm = "md5RSA(OIW)";
- else if (pszObjId == szOID_RSA_MD2RSA)
- info.SignAlgorithm = "md2RSA(RSA)";
- else if (pszObjId == szOID_RSA_SHA256RSA)
- info.SignAlgorithm = "sha256RSA(RSA)";
- else
- info.SignAlgorithm = StripString(pszObjId);
-
- return true;
- }
-
private static bool SafeToReadNBytes(uint size, uint start, uint requestSize)
=> size - start >= requestSize;
@@ -1152,7 +1025,6 @@ private static string TimeToString(IntPtr pftIn, IntPtr pstIn = 0)
class SignCounterSign
{
- public string SignerName { get; set; } = string.Empty;
public string TimeStamp { get; set; } = string.Empty;
}
@@ -1161,8 +1033,9 @@ class SignNodeInfo
public bool IsValid { get; set; } = false;
public string DigestAlgorithm { get; set; } = string.Empty;
public string Version { get; set; } = string.Empty;
+ public int Index { get; set; } = 0;
public SignCounterSign CounterSign { get; set; } = new();
- public List CertChain = new();
+ public List CertChain = [];
}
}
}
diff --git a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
index 65d0554c1c31..e93a411f0803 100644
--- a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using Files.App.Utils.Signatures;
+using Microsoft.UI.Windowing;
namespace Files.App.ViewModels.Properties
{
@@ -11,12 +12,17 @@ public sealed partial class SignaturesViewModel : ObservableObject, IDisposable
public ObservableCollection Signatures { get; set; }
- public SignaturesViewModel(ListedItem item)
+ public SignaturesViewModel(ListedItem item, AppWindow appWindow)
{
_cancellationTokenSource = new();
Signatures = new();
-
- DigitalSignaturesUtil.LoadItemSignatures(item.ItemPath, Signatures);
+ var hWnd = Microsoft.UI.Win32Interop.GetWindowFromWindowId(appWindow.Id);
+ DigitalSignaturesUtil.LoadItemSignatures(
+ item.ItemPath,
+ Signatures,
+ hWnd,
+ _cancellationTokenSource.Token
+ );
}
public void Dispose()
diff --git a/src/Files.App/Views/Properties/SignaturesPage.xaml.cs b/src/Files.App/Views/Properties/SignaturesPage.xaml.cs
index 214f70bf2b54..01ad04bdd6a4 100644
--- a/src/Files.App/Views/Properties/SignaturesPage.xaml.cs
+++ b/src/Files.App/Views/Properties/SignaturesPage.xaml.cs
@@ -19,7 +19,7 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
{
var np = (PropertiesPageNavigationParameter)e.Parameter;
if (np.Parameter is ListedItem listedItem)
- SignaturesViewModel = new(listedItem);
+ SignaturesViewModel = new(listedItem, np.Window.AppWindow);
base.OnNavigatedTo(e);
}
From 467b6db5b2dc6489e2b84b39f2bdcfbd190dd674 Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Sun, 27 Jul 2025 22:43:19 +0200
Subject: [PATCH 04/10] Spacing Issues
---
.../PropertiesNavigationViewItemFactory.cs | 40 +-
src/Files.App/Data/Items/CertNodeInfoItem.cs | 12 +-
.../Data/Models/SignatureInfoItem.cs | 164 +-
.../Helpers/Win32/Win32PInvoke.Methods.cs | 948 ++++----
.../Helpers/Win32/Win32PInvoke.Structs.cs | 696 +++---
.../Utils/Signatures/DigitalSignaturesUtil.cs | 2064 ++++++++---------
.../Properties/MainPropertiesViewModel.cs | 16 +-
.../Properties/SignaturesViewModel.cs | 42 +-
.../Views/Properties/SignaturesPage.xaml | 2 +-
.../Views/Properties/SignaturesPage.xaml.cs | 62 +-
10 files changed, 2023 insertions(+), 2023 deletions(-)
diff --git a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
index 44b0c569740d..7e4efccd40b6 100644
--- a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
+++ b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
@@ -61,16 +61,16 @@ public static ObservableCollection Initialize
ItemType = PropertiesNavigationViewItemType.Compatibility,
ThemedIconStyle = (Style)Application.Current.Resources["App.ThemedIcons.Properties.Compatability"],
};
- var signaturesItem = new NavigationViewItemButtonStyleItem()
- {
- Name = Strings.Signatures.GetLocalizedResource(),
- ItemType = PropertiesNavigationViewItemType.Signatures,
- ThemedIconStyle = (Style)Application.Current.Resources["App.ThemedIcons.Properties.Signatures"],
- };
-
- PropertiesNavigationViewItems.Add(generalItem);
- PropertiesNavigationViewItems.Add(signaturesItem);
- PropertiesNavigationViewItems.Add(securityItem);
+ var signaturesItem = new NavigationViewItemButtonStyleItem()
+ {
+ Name = Strings.Signatures.GetLocalizedResource(),
+ ItemType = PropertiesNavigationViewItemType.Signatures,
+ ThemedIconStyle = (Style)Application.Current.Resources["App.ThemedIcons.Properties.Signatures"],
+ };
+
+ PropertiesNavigationViewItems.Add(generalItem);
+ PropertiesNavigationViewItems.Add(signaturesItem);
+ PropertiesNavigationViewItems.Add(securityItem);
PropertiesNavigationViewItems.Add(hashesItem);
PropertiesNavigationViewItems.Add(shortcutItem);
PropertiesNavigationViewItems.Add(libraryItem);
@@ -96,8 +96,8 @@ public static ObservableCollection Initialize
PropertiesNavigationViewItems.Remove(securityItem);
PropertiesNavigationViewItems.Remove(customizationItem);
PropertiesNavigationViewItems.Remove(hashesItem);
- PropertiesNavigationViewItems.Remove(signaturesItem);
- }
+ PropertiesNavigationViewItems.Remove(signaturesItem);
+ }
else if (item is ListedItem listedItem)
{
var isShortcut = listedItem.IsShortcut;
@@ -114,13 +114,13 @@ public static ObservableCollection Initialize
if (!securityItemEnabled)
PropertiesNavigationViewItems.Remove(securityItem);
- if (!hashItemEnabled)
- {
- PropertiesNavigationViewItems.Remove(hashesItem);
- PropertiesNavigationViewItems.Remove(signaturesItem);
- }
+ if (!hashItemEnabled)
+ {
+ PropertiesNavigationViewItems.Remove(hashesItem);
+ PropertiesNavigationViewItems.Remove(signaturesItem);
+ }
- if (!isShortcut)
+ if (!isShortcut)
PropertiesNavigationViewItems.Remove(shortcutItem);
if (!isLibrary)
@@ -143,8 +143,8 @@ public static ObservableCollection Initialize
PropertiesNavigationViewItems.Remove(detailsItem);
PropertiesNavigationViewItems.Remove(customizationItem);
PropertiesNavigationViewItems.Remove(compatibilityItem);
- PropertiesNavigationViewItems.Remove(signaturesItem);
- }
+ PropertiesNavigationViewItems.Remove(signaturesItem);
+ }
return PropertiesNavigationViewItems;
}
diff --git a/src/Files.App/Data/Items/CertNodeInfoItem.cs b/src/Files.App/Data/Items/CertNodeInfoItem.cs
index 3c5e9b131f7b..abed64927c7a 100644
--- a/src/Files.App/Data/Items/CertNodeInfoItem.cs
+++ b/src/Files.App/Data/Items/CertNodeInfoItem.cs
@@ -5,14 +5,14 @@ namespace Files.App.Data.Items
{
public class CertNodeInfoItem
{
- public string IssuedTo { get; set; } = string.Empty;
+ public string IssuedTo { get; set; } = string.Empty;
- public string IssuedBy { get; set; } = string.Empty;
+ public string IssuedBy { get; set; } = string.Empty;
- public string Version { get; set; } = string.Empty;
+ public string Version { get; set; } = string.Empty;
- public string ValidFrom { get; set; } = string.Empty;
+ public string ValidFrom { get; set; } = string.Empty;
- public string ValidTo { get; set; } = string.Empty;
- }
+ public string ValidTo { get; set; } = string.Empty;
+ }
}
diff --git a/src/Files.App/Data/Models/SignatureInfoItem.cs b/src/Files.App/Data/Models/SignatureInfoItem.cs
index 11e06cea0a15..d58fb5b4eab4 100644
--- a/src/Files.App/Data/Models/SignatureInfoItem.cs
+++ b/src/Files.App/Data/Models/SignatureInfoItem.cs
@@ -6,86 +6,86 @@
namespace Files.App.Data.Models
{
- public sealed partial class SignatureInfoItem : ObservableObject
- {
- private readonly string _fileName;
-
- private readonly IntPtr _hwndParent;
-
- private readonly int _index;
-
- private string _Version = string.Empty;
- public string Version
- {
- get => _Version;
- set => SetProperty(ref _Version, value);
- }
-
- private string _IssuedBy = string.Empty;
- public string IssuedBy
- {
- get => _IssuedBy;
- set => SetProperty(ref _IssuedBy, value);
- }
-
- private string _IssuedTo = string.Empty;
- public string IssuedTo
- {
- get => _IssuedTo;
- set => SetProperty(ref _IssuedTo, value);
- }
-
- private string _ValidFromTimestamp = string.Empty;
- public string ValidFromTimestamp
- {
- get => _ValidFromTimestamp;
- set => SetProperty(ref _ValidFromTimestamp, value);
- }
-
- private string _ValidToTimestamp = string.Empty;
- public string ValidToTimestamp
- {
- get => _ValidToTimestamp;
- set => SetProperty(ref _ValidToTimestamp, value);
- }
-
- private string _VerifiedTimestamp = string.Empty;
- public string VerifiedTimestamp
- {
- get => _VerifiedTimestamp;
- set => SetProperty(ref _VerifiedTimestamp, value);
- }
-
- private bool _Verified = false;
- public bool Verified
- {
- get => _Verified;
- set
- {
- if (SetProperty(ref _Verified, value))
- OnPropertyChanged(nameof(Glyph));
- }
- }
-
- public List SignChain { get; }
-
- public string Glyph => Verified ? "\uE930" : "\uEA39";
-
- public ICommand OpenDetailsCommand { get; }
-
- public SignatureInfoItem(string fileName, int index, IntPtr hWnd, List chain)
- {
- _fileName = fileName;
- _hwndParent = hWnd;
- _index = index;
- SignChain = chain ?? new List();
- OpenDetailsCommand = new AsyncRelayCommand(DoOpenDetails);
- }
-
- private Task DoOpenDetails()
- {
- DigitalSignaturesUtil.DisplaySignerInfoDialog(_fileName, _hwndParent, _index);
- return Task.CompletedTask;
- }
- }
+ public sealed partial class SignatureInfoItem : ObservableObject
+ {
+ private readonly string _fileName;
+
+ private readonly IntPtr _hwndParent;
+
+ private readonly int _index;
+
+ private string _Version = string.Empty;
+ public string Version
+ {
+ get => _Version;
+ set => SetProperty(ref _Version, value);
+ }
+
+ private string _IssuedBy = string.Empty;
+ public string IssuedBy
+ {
+ get => _IssuedBy;
+ set => SetProperty(ref _IssuedBy, value);
+ }
+
+ private string _IssuedTo = string.Empty;
+ public string IssuedTo
+ {
+ get => _IssuedTo;
+ set => SetProperty(ref _IssuedTo, value);
+ }
+
+ private string _ValidFromTimestamp = string.Empty;
+ public string ValidFromTimestamp
+ {
+ get => _ValidFromTimestamp;
+ set => SetProperty(ref _ValidFromTimestamp, value);
+ }
+
+ private string _ValidToTimestamp = string.Empty;
+ public string ValidToTimestamp
+ {
+ get => _ValidToTimestamp;
+ set => SetProperty(ref _ValidToTimestamp, value);
+ }
+
+ private string _VerifiedTimestamp = string.Empty;
+ public string VerifiedTimestamp
+ {
+ get => _VerifiedTimestamp;
+ set => SetProperty(ref _VerifiedTimestamp, value);
+ }
+
+ private bool _Verified = false;
+ public bool Verified
+ {
+ get => _Verified;
+ set
+ {
+ if (SetProperty(ref _Verified, value))
+ OnPropertyChanged(nameof(Glyph));
+ }
+ }
+
+ public List SignChain { get; }
+
+ public string Glyph => Verified ? "\uE930" : "\uEA39";
+
+ public ICommand OpenDetailsCommand { get; }
+
+ public SignatureInfoItem(string fileName, int index, IntPtr hWnd, List chain)
+ {
+ _fileName = fileName;
+ _hwndParent = hWnd;
+ _index = index;
+ SignChain = chain ?? new List();
+ OpenDetailsCommand = new AsyncRelayCommand(DoOpenDetails);
+ }
+
+ private Task DoOpenDetails()
+ {
+ DigitalSignaturesUtil.DisplaySignerInfoDialog(_fileName, _hwndParent, _index);
+ return Task.CompletedTask;
+ }
+ }
}
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
index ae2022366db4..7ff329b089b1 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
@@ -9,478 +9,478 @@
namespace Files.App.Helpers
{
- public static partial class Win32PInvoke
- {
- public delegate void LpoverlappedCompletionRoutine(
- uint dwErrorCode,
- uint dwNumberOfBytesTransfered,
- OVERLAPPED lpOverlapped
- );
-
- public delegate void LPOVERLAPPED_COMPLETION_ROUTINE(
- uint dwErrorCode,
- uint dwNumberOfBytesTransfered,
- ref NativeOverlapped lpOverlapped
- );
-
- [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
- public static extern int RmRegisterResources(
- uint pSessionHandle,
- uint nFiles,
- string[] rgsFilenames,
- uint nApplications,
- [In] RM_UNIQUE_PROCESS[] rgApplications,
- uint nServices,
- string[] rgsServiceNames
- );
-
- [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
- public static extern int RmStartSession(
- out uint pSessionHandle,
- int dwSessionFlags,
- string strSessionKey
- );
-
- [DllImport("rstrtmgr.dll")]
- public static extern int RmEndSession(
- uint pSessionHandle
- );
-
- [DllImport("rstrtmgr.dll")]
- public static extern int RmGetList(
- uint dwSessionHandle,
- out uint pnProcInfoNeeded,
- ref uint pnProcInfo,
- [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
- ref uint lpdwRebootReasons
- );
-
- [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- public static extern IntPtr CreateEvent(
- IntPtr lpEventAttributes,
- bool bManualReset,
- bool bInitialState,
- string lpName
- );
-
- [DllImport("kernel32.dll")]
- public static extern bool SetEvent(
- IntPtr hEvent
- );
-
- [DllImport("ole32.dll")]
- public static extern uint CoWaitForMultipleObjects(
- uint dwFlags,
- uint dwMilliseconds,
- ulong nHandles,
- IntPtr[] pHandles,
- out uint dwIndex
- );
-
- [DllImport("shell32.dll")]
- public static extern IntPtr SHBrowseForFolder(
- ref BROWSEINFO lpbi
- );
-
- [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
- public static extern bool SHGetPathFromIDList(
- IntPtr pidl,
- [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath
- );
-
- [DllImport("api-ms-win-core-handle-l1-1-0.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool CloseHandle(
- IntPtr hObject
- );
-
- [DllImport("api-ms-win-core-io-l1-1-1.dll")]
- public static extern bool CancelIoEx(
- IntPtr hFile,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-synch-l1-2-0.dll", SetLastError = true)]
- public static extern uint WaitForSingleObjectEx(
- IntPtr hHandle,
- uint dwMilliseconds,
- bool bAlertable
- );
-
- [DllImport("api-ms-win-core-file-l2-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public unsafe static extern bool ReadDirectoryChangesW(
- IntPtr hDirectory,
- byte* lpBuffer,
- int nBufferLength,
- bool bWatchSubtree,
- int dwNotifyFilter,
- int* lpBytesReturned,
- ref OVERLAPPED lpOverlapped,
- LpoverlappedCompletionRoutine lpCompletionRoutine
- );
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
- public static extern IntPtr CreateFileFromAppW(
- string lpFileName,
- uint dwDesiredAccess,
- uint dwShareMode,
- IntPtr SecurityAttributes,
- uint dwCreationDisposition,
- uint dwFlagsAndAttributes,
- IntPtr hTemplateFile
- );
-
- [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
- public static extern bool DeviceIoControl(
- IntPtr hDevice,
- uint dwIoControlCode,
- IntPtr lpInBuffer,
- uint nInBufferSize,
- IntPtr lpOutBuffer,
- uint nOutBufferSize,
- out uint lpBytesReturned,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
- public static extern bool DeviceIoControl(
- IntPtr hDevice,
- uint dwIoControlCode,
- byte[] lpInBuffer,
- uint nInBufferSize,
- IntPtr lpOutBuffer,
- uint nOutBufferSize,
- out uint lpBytesReturned,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool DeviceIoControl(
- IntPtr hDevice,
- uint dwIoControlCode,
- IntPtr lpInBuffer,
- uint nInBufferSize,
- //IntPtr lpOutBuffer,
- out REPARSE_DATA_BUFFER outBuffer,
- uint nOutBufferSize,
- out uint lpBytesReturned,
- IntPtr lpOverlapped);
-
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
- public static extern int ToUnicodeEx(
- uint virtualKeyCode,
- uint scanCode,
- byte[] keyboardState,
- [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder receivingBuffer,
- int bufferSize,
- uint flags,
- IntPtr keyboardLayout
- );
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern IntPtr CreateFileFromApp(
- string lpFileName,
- uint dwDesiredAccess,
- uint dwShareMode,
- IntPtr SecurityAttributes,
- uint dwCreationDisposition,
- uint dwFlagsAndAttributes,
- IntPtr hTemplateFile
- );
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool GetFileAttributesExFromApp(
- string lpFileName,
- GET_FILEEX_INFO_LEVELS fInfoLevelId,
- out WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool SetFileAttributesFromApp(
- string lpFileName,
- FileAttributes dwFileAttributes);
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public unsafe static extern bool ReadFile(
- IntPtr hFile,
- byte* lpBuffer,
- int nBufferLength,
- int* lpBytesReturned,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public unsafe static extern bool WriteFile(
- IntPtr hFile,
- byte* lpBuffer,
- int nBufferLength,
- int* lpBytesWritten,
- IntPtr lpOverlapped
- );
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern bool WriteFileEx(
- IntPtr hFile,
- byte[] lpBuffer,
- uint nNumberOfBytesToWrite,
- [In] ref NativeOverlapped lpOverlapped,
- LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern bool GetFileTime(
- [In] IntPtr hFile,
- out System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
- out System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
- out System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime
- );
-
- [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern bool SetFileTime(
- [In] IntPtr hFile,
- in System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
- in System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
- in System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime
- );
-
- [DllImport("api-ms-win-core-file-l2-1-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- public static extern bool GetFileInformationByHandleEx(
- IntPtr hFile,
- FILE_INFO_BY_HANDLE_CLASS infoClass,
- out FILE_ID_BOTH_DIR_INFO dirInfo,
- uint dwBufferSize
- );
-
- [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
- public static extern IntPtr FindFirstStreamW(
- string lpFileName,
- StreamInfoLevels InfoLevel,
- [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData,
- uint dwFlags
- );
-
- [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool FindNextStreamW(
- IntPtr hndFindFile,
- [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData
- );
-
- [DllImport("api-ms-win-core-wow64-l1-1-1.dll", SetLastError = true)]
- public static extern bool IsWow64Process2(
- IntPtr process,
- out ushort processMachine,
- out ushort nativeMachine
- );
-
- [DllImport("api-ms-win-core-file-l1-1-0.dll", CharSet = CharSet.Unicode)]
- public static extern bool FindNextFile(
- IntPtr hFindFile,
- out WIN32_FIND_DATA lpFindFileData
- );
-
- [DllImport("api-ms-win-core-file-l1-1-0.dll")]
- public static extern bool FindClose(
- IntPtr hFindFile
- );
-
- [DllImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)]
- public static extern bool FileTimeToSystemTime(
- ref System.Runtime.InteropServices.ComTypes.FILETIME lpFileTime,
- out SYSTEMTIME lpSystemTime
- );
-
- [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern IntPtr FindFirstFileExFromApp(
- string lpFileName,
- FINDEX_INFO_LEVELS fInfoLevelId,
- out WIN32_FIND_DATA lpFindFileData,
- FINDEX_SEARCH_OPS fSearchOp,
- IntPtr lpSearchFilter,
- int dwAdditionalFlags
- );
-
- [LibraryImport("shell32.dll", EntryPoint = "#865", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static partial bool IsElevationRequired(
- [MarshalAs(UnmanagedType.LPWStr)] string pszPath);
-
- [DllImport("shlwapi.dll", CallingConvention = CallingConvention.StdCall, PreserveSig = true, CharSet = CharSet.Unicode)]
- public static extern HRESULT SHCreateStreamOnFileEx(
- string pszFile,
- STGM grfMode,
- uint dwAttributes,
- uint fCreate,
- IntPtr pstmTemplate,
- out IntPtr ppstm
- );
-
- [DllImport("shell32.dll", CallingConvention = CallingConvention.StdCall, PreserveSig = true, CharSet = CharSet.Unicode)]
- public static extern HRESULT SHCreateItemFromParsingName(
- string pszPath,
- IntPtr pbc,
- ref Guid riid,
- out IntPtr ppv
- );
-
- [DllImport("ole32.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern HRESULT CoCreateInstance(
- ref Guid rclsid,
- IntPtr pUnkOuter,
- ClassContext dwClsContext,
- ref Guid riid,
- out IntPtr ppv
- );
-
- [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- public static extern uint RegisterApplicationRestart(
- string pwzCommandLine,
- int dwFlags
- );
-
- [DllImport("shell32.dll")]
- public static extern int SHGetKnownFolderPath(
- [MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
- uint dwFlags,
- IntPtr hToken,
- out IntPtr pszPath
- );
-
- // crypt32.dll
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern uint CertGetNameStringA(
- IntPtr pCertContext,
- uint dwType,
- uint dwFlags,
- IntPtr pvTypePara,
- IntPtr pszNameString,
- uint cchNameString
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CertFreeCertificateContext(
- IntPtr pCertContext
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptMsgGetParam(
- IntPtr hCryptMsg,
- uint dwParamType,
- uint dwIndex,
- IntPtr pParam,
- ref uint dwOutSize
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptMsgClose(
- IntPtr hCryptMsg
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern IntPtr CryptMsgOpenToDecode(
- uint dwMsgEncodingType,
- uint dwFlags,
- uint dwMsgType,
- IntPtr hCryptProv,
- IntPtr pRecipientInfo,
- IntPtr pStreamInfo
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptMsgUpdate(
- IntPtr hCryptMsg,
- IntPtr pbData,
- uint cbDatam,
- bool fFinal
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern IntPtr CertOpenStore(
- IntPtr lpszStoreProvider,
- uint dwEncodingType,
- IntPtr hCryptProv,
- uint dwFlags,
- IntPtr pvPara
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptDecodeObject(
- uint dwCertEncodingType,
- IntPtr lpszStructType,
- IntPtr pbEncoded,
- uint cbEncoded,
- uint dwFlags,
- IntPtr pvStructInfo,
- ref uint pcbStructInfo
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern IntPtr CertFindCertificateInStore(
- IntPtr hCertStore,
- uint dwCertEncodingType,
- uint dwFindFlags,
- uint dwFindType,
- IntPtr pvFindPara,
- IntPtr pPrevCertContext
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CertComparePublicKeyInfo(
- uint dwCertEncodingType,
- IntPtr pPublicKey1,
- IntPtr pPublicKey2
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptQueryObject(
- uint dwObjectType,
- IntPtr pvObject,
- uint dwExpectedContentTypeFlags,
- uint dwExpectedFormatTypeFlags,
- uint dwFlags,
- ref uint pdwMsgAndCertEncodingType,
- ref uint pdwContentType,
- ref uint pdwFormatType,
- ref IntPtr phCertStore,
- ref IntPtr phMsg,
- ref IntPtr ppvContext
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CertCloseStore(
- IntPtr hCertStore,
- uint dwFlags
- );
-
- [DllImport("wintrust.dll")]
- public static extern long WinVerifyTrust(
- IntPtr hwnd,
- IntPtr pgActionID,
- IntPtr pWVTData
- );
-
- // kernel32.dll
- [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool FileTimeToSystemTime(
- IntPtr lpFileTime,
- IntPtr lpSystemTime
- );
-
- [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool FileTimeToLocalFileTime(
- IntPtr lpFileTime,
- IntPtr lpLocalFileTime
- );
-
- [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool SystemTimeToFileTime(
- IntPtr lpSystemTime,
- IntPtr lpFileTime
- );
-
- // cryptui.dll
- [DllImport("cryptui.dll", SetLastError = true, CharSet = CharSet.Auto)]
- public static extern bool CryptUIDlgViewSignerInfo(IntPtr pViewInfo);
- }
+ public static partial class Win32PInvoke
+ {
+ public delegate void LpoverlappedCompletionRoutine(
+ uint dwErrorCode,
+ uint dwNumberOfBytesTransfered,
+ OVERLAPPED lpOverlapped
+ );
+
+ public delegate void LPOVERLAPPED_COMPLETION_ROUTINE(
+ uint dwErrorCode,
+ uint dwNumberOfBytesTransfered,
+ ref NativeOverlapped lpOverlapped
+ );
+
+ [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
+ public static extern int RmRegisterResources(
+ uint pSessionHandle,
+ uint nFiles,
+ string[] rgsFilenames,
+ uint nApplications,
+ [In] RM_UNIQUE_PROCESS[] rgApplications,
+ uint nServices,
+ string[] rgsServiceNames
+ );
+
+ [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
+ public static extern int RmStartSession(
+ out uint pSessionHandle,
+ int dwSessionFlags,
+ string strSessionKey
+ );
+
+ [DllImport("rstrtmgr.dll")]
+ public static extern int RmEndSession(
+ uint pSessionHandle
+ );
+
+ [DllImport("rstrtmgr.dll")]
+ public static extern int RmGetList(
+ uint dwSessionHandle,
+ out uint pnProcInfoNeeded,
+ ref uint pnProcInfo,
+ [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
+ ref uint lpdwRebootReasons
+ );
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
+ public static extern IntPtr CreateEvent(
+ IntPtr lpEventAttributes,
+ bool bManualReset,
+ bool bInitialState,
+ string lpName
+ );
+
+ [DllImport("kernel32.dll")]
+ public static extern bool SetEvent(
+ IntPtr hEvent
+ );
+
+ [DllImport("ole32.dll")]
+ public static extern uint CoWaitForMultipleObjects(
+ uint dwFlags,
+ uint dwMilliseconds,
+ ulong nHandles,
+ IntPtr[] pHandles,
+ out uint dwIndex
+ );
+
+ [DllImport("shell32.dll")]
+ public static extern IntPtr SHBrowseForFolder(
+ ref BROWSEINFO lpbi
+ );
+
+ [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
+ public static extern bool SHGetPathFromIDList(
+ IntPtr pidl,
+ [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath
+ );
+
+ [DllImport("api-ms-win-core-handle-l1-1-0.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CloseHandle(
+ IntPtr hObject
+ );
+
+ [DllImport("api-ms-win-core-io-l1-1-1.dll")]
+ public static extern bool CancelIoEx(
+ IntPtr hFile,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-synch-l1-2-0.dll", SetLastError = true)]
+ public static extern uint WaitForSingleObjectEx(
+ IntPtr hHandle,
+ uint dwMilliseconds,
+ bool bAlertable
+ );
+
+ [DllImport("api-ms-win-core-file-l2-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public unsafe static extern bool ReadDirectoryChangesW(
+ IntPtr hDirectory,
+ byte* lpBuffer,
+ int nBufferLength,
+ bool bWatchSubtree,
+ int dwNotifyFilter,
+ int* lpBytesReturned,
+ ref OVERLAPPED lpOverlapped,
+ LpoverlappedCompletionRoutine lpCompletionRoutine
+ );
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern IntPtr CreateFileFromAppW(
+ string lpFileName,
+ uint dwDesiredAccess,
+ uint dwShareMode,
+ IntPtr SecurityAttributes,
+ uint dwCreationDisposition,
+ uint dwFlagsAndAttributes,
+ IntPtr hTemplateFile
+ );
+
+ [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool DeviceIoControl(
+ IntPtr hDevice,
+ uint dwIoControlCode,
+ IntPtr lpInBuffer,
+ uint nInBufferSize,
+ IntPtr lpOutBuffer,
+ uint nOutBufferSize,
+ out uint lpBytesReturned,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool DeviceIoControl(
+ IntPtr hDevice,
+ uint dwIoControlCode,
+ byte[] lpInBuffer,
+ uint nInBufferSize,
+ IntPtr lpOutBuffer,
+ uint nOutBufferSize,
+ out uint lpBytesReturned,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-io-l1-1-0.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DeviceIoControl(
+ IntPtr hDevice,
+ uint dwIoControlCode,
+ IntPtr lpInBuffer,
+ uint nInBufferSize,
+ //IntPtr lpOutBuffer,
+ out REPARSE_DATA_BUFFER outBuffer,
+ uint nOutBufferSize,
+ out uint lpBytesReturned,
+ IntPtr lpOverlapped);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ public static extern int ToUnicodeEx(
+ uint virtualKeyCode,
+ uint scanCode,
+ byte[] keyboardState,
+ [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder receivingBuffer,
+ int bufferSize,
+ uint flags,
+ IntPtr keyboardLayout
+ );
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern IntPtr CreateFileFromApp(
+ string lpFileName,
+ uint dwDesiredAccess,
+ uint dwShareMode,
+ IntPtr SecurityAttributes,
+ uint dwCreationDisposition,
+ uint dwFlagsAndAttributes,
+ IntPtr hTemplateFile
+ );
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetFileAttributesExFromApp(
+ string lpFileName,
+ GET_FILEEX_INFO_LEVELS fInfoLevelId,
+ out WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetFileAttributesFromApp(
+ string lpFileName,
+ FileAttributes dwFileAttributes);
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public unsafe static extern bool ReadFile(
+ IntPtr hFile,
+ byte* lpBuffer,
+ int nBufferLength,
+ int* lpBytesReturned,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public unsafe static extern bool WriteFile(
+ IntPtr hFile,
+ byte* lpBuffer,
+ int nBufferLength,
+ int* lpBytesWritten,
+ IntPtr lpOverlapped
+ );
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern bool WriteFileEx(
+ IntPtr hFile,
+ byte[] lpBuffer,
+ uint nNumberOfBytesToWrite,
+ [In] ref NativeOverlapped lpOverlapped,
+ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern bool GetFileTime(
+ [In] IntPtr hFile,
+ out System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
+ out System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
+ out System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime
+ );
+
+ [DllImport("api-ms-win-core-file-l1-2-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern bool SetFileTime(
+ [In] IntPtr hFile,
+ in System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
+ in System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
+ in System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime
+ );
+
+ [DllImport("api-ms-win-core-file-l2-1-1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+ public static extern bool GetFileInformationByHandleEx(
+ IntPtr hFile,
+ FILE_INFO_BY_HANDLE_CLASS infoClass,
+ out FILE_ID_BOTH_DIR_INFO dirInfo,
+ uint dwBufferSize
+ );
+
+ [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern IntPtr FindFirstStreamW(
+ string lpFileName,
+ StreamInfoLevels InfoLevel,
+ [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData,
+ uint dwFlags
+ );
+
+ [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool FindNextStreamW(
+ IntPtr hndFindFile,
+ [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData
+ );
+
+ [DllImport("api-ms-win-core-wow64-l1-1-1.dll", SetLastError = true)]
+ public static extern bool IsWow64Process2(
+ IntPtr process,
+ out ushort processMachine,
+ out ushort nativeMachine
+ );
+
+ [DllImport("api-ms-win-core-file-l1-1-0.dll", CharSet = CharSet.Unicode)]
+ public static extern bool FindNextFile(
+ IntPtr hFindFile,
+ out WIN32_FIND_DATA lpFindFileData
+ );
+
+ [DllImport("api-ms-win-core-file-l1-1-0.dll")]
+ public static extern bool FindClose(
+ IntPtr hFindFile
+ );
+
+ [DllImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)]
+ public static extern bool FileTimeToSystemTime(
+ ref System.Runtime.InteropServices.ComTypes.FILETIME lpFileTime,
+ out SYSTEMTIME lpSystemTime
+ );
+
+ [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr FindFirstFileExFromApp(
+ string lpFileName,
+ FINDEX_INFO_LEVELS fInfoLevelId,
+ out WIN32_FIND_DATA lpFindFileData,
+ FINDEX_SEARCH_OPS fSearchOp,
+ IntPtr lpSearchFilter,
+ int dwAdditionalFlags
+ );
+
+ [LibraryImport("shell32.dll", EntryPoint = "#865", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static partial bool IsElevationRequired(
+ [MarshalAs(UnmanagedType.LPWStr)] string pszPath);
+
+ [DllImport("shlwapi.dll", CallingConvention = CallingConvention.StdCall, PreserveSig = true, CharSet = CharSet.Unicode)]
+ public static extern HRESULT SHCreateStreamOnFileEx(
+ string pszFile,
+ STGM grfMode,
+ uint dwAttributes,
+ uint fCreate,
+ IntPtr pstmTemplate,
+ out IntPtr ppstm
+ );
+
+ [DllImport("shell32.dll", CallingConvention = CallingConvention.StdCall, PreserveSig = true, CharSet = CharSet.Unicode)]
+ public static extern HRESULT SHCreateItemFromParsingName(
+ string pszPath,
+ IntPtr pbc,
+ ref Guid riid,
+ out IntPtr ppv
+ );
+
+ [DllImport("ole32.dll", CallingConvention = CallingConvention.StdCall)]
+ public static extern HRESULT CoCreateInstance(
+ ref Guid rclsid,
+ IntPtr pUnkOuter,
+ ClassContext dwClsContext,
+ ref Guid riid,
+ out IntPtr ppv
+ );
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
+ public static extern uint RegisterApplicationRestart(
+ string pwzCommandLine,
+ int dwFlags
+ );
+
+ [DllImport("shell32.dll")]
+ public static extern int SHGetKnownFolderPath(
+ [MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
+ uint dwFlags,
+ IntPtr hToken,
+ out IntPtr pszPath
+ );
+
+ // crypt32.dll
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern uint CertGetNameStringA(
+ IntPtr pCertContext,
+ uint dwType,
+ uint dwFlags,
+ IntPtr pvTypePara,
+ IntPtr pszNameString,
+ uint cchNameString
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CertFreeCertificateContext(
+ IntPtr pCertContext
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptMsgGetParam(
+ IntPtr hCryptMsg,
+ uint dwParamType,
+ uint dwIndex,
+ IntPtr pParam,
+ ref uint dwOutSize
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptMsgClose(
+ IntPtr hCryptMsg
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr CryptMsgOpenToDecode(
+ uint dwMsgEncodingType,
+ uint dwFlags,
+ uint dwMsgType,
+ IntPtr hCryptProv,
+ IntPtr pRecipientInfo,
+ IntPtr pStreamInfo
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptMsgUpdate(
+ IntPtr hCryptMsg,
+ IntPtr pbData,
+ uint cbDatam,
+ bool fFinal
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr CertOpenStore(
+ IntPtr lpszStoreProvider,
+ uint dwEncodingType,
+ IntPtr hCryptProv,
+ uint dwFlags,
+ IntPtr pvPara
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptDecodeObject(
+ uint dwCertEncodingType,
+ IntPtr lpszStructType,
+ IntPtr pbEncoded,
+ uint cbEncoded,
+ uint dwFlags,
+ IntPtr pvStructInfo,
+ ref uint pcbStructInfo
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr CertFindCertificateInStore(
+ IntPtr hCertStore,
+ uint dwCertEncodingType,
+ uint dwFindFlags,
+ uint dwFindType,
+ IntPtr pvFindPara,
+ IntPtr pPrevCertContext
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CertComparePublicKeyInfo(
+ uint dwCertEncodingType,
+ IntPtr pPublicKey1,
+ IntPtr pPublicKey2
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CryptQueryObject(
+ uint dwObjectType,
+ IntPtr pvObject,
+ uint dwExpectedContentTypeFlags,
+ uint dwExpectedFormatTypeFlags,
+ uint dwFlags,
+ ref uint pdwMsgAndCertEncodingType,
+ ref uint pdwContentType,
+ ref uint pdwFormatType,
+ ref IntPtr phCertStore,
+ ref IntPtr phMsg,
+ ref IntPtr ppvContext
+ );
+
+ [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool CertCloseStore(
+ IntPtr hCertStore,
+ uint dwFlags
+ );
+
+ [DllImport("wintrust.dll")]
+ public static extern long WinVerifyTrust(
+ IntPtr hwnd,
+ IntPtr pgActionID,
+ IntPtr pWVTData
+ );
+
+ // kernel32.dll
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool FileTimeToSystemTime(
+ IntPtr lpFileTime,
+ IntPtr lpSystemTime
+ );
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool FileTimeToLocalFileTime(
+ IntPtr lpFileTime,
+ IntPtr lpLocalFileTime
+ );
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern bool SystemTimeToFileTime(
+ IntPtr lpSystemTime,
+ IntPtr lpFileTime
+ );
+
+ // cryptui.dll
+ [DllImport("cryptui.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool CryptUIDlgViewSignerInfo(IntPtr pViewInfo);
+ }
}
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
index 414eb64ec9a6..0ba1c5f1bca3 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
@@ -6,352 +6,352 @@
namespace Files.App.Helpers
{
- public static partial class Win32PInvoke
- {
- [StructLayout(LayoutKind.Sequential)]
- public struct RM_UNIQUE_PROCESS
- {
- public int dwProcessId;
- public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct RM_PROCESS_INFO
- {
- public RM_UNIQUE_PROCESS Process;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
- public string strAppName;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
- public string strServiceShortName;
-
- public RM_APP_TYPE ApplicationType;
- public uint AppStatus;
- public uint TSSessionId;
- [MarshalAs(UnmanagedType.Bool)]
- public bool bRestartable;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct BROWSEINFO
- {
- public IntPtr hwndOwner;
- public IntPtr pidlRoot;
- public string pszDisplayName;
- public string lpszTitle;
- public uint ulFlags;
- public IntPtr lpfn;
- public int lParam;
- public IntPtr iImage;
- }
-
- public unsafe struct OVERLAPPED
- {
- public IntPtr Internal;
- public IntPtr InternalHigh;
- public Union PointerAndOffset;
- public IntPtr hEvent;
-
- [StructLayout(LayoutKind.Explicit)]
- public struct Union
- {
- [FieldOffset(0)] public void* IntPtr;
- [FieldOffset(0)] public OffsetPair Offset;
-
- public struct OffsetPair { public uint Offset; public uint OffsetHigh; }
- }
- }
-
- public unsafe struct FILE_NOTIFY_INFORMATION
- {
- public uint NextEntryOffset;
- public uint Action;
- public uint FileNameLength;
- public fixed char FileName[1];
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct REPARSE_DATA_BUFFER
- {
- public uint ReparseTag;
- public short ReparseDataLength;
- public short Reserved;
- public short SubsNameOffset;
- public short SubsNameLength;
- public short PrintNameOffset;
- public short PrintNameLength;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_REPARSE_DATA_BUFFER_SIZE)]
- public char[] PathBuffer;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct WIN32_FILE_ATTRIBUTE_DATA
- {
- public FileAttributes dwFileAttributes;
- public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
- public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
- public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct FILE_ID_BOTH_DIR_INFO
- {
- public uint NextEntryOffset;
- public uint FileIndex;
- public long CreationTime;
- public long LastAccessTime;
- public long LastWriteTime;
- public long ChangeTime;
- public long EndOfFile;
- public long AllocationSize;
- public uint FileAttributes;
- public uint FileNameLength;
- public uint EaSize;
- public char ShortNameLength;
- [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 12)]
- public string ShortName;
- public long FileId;
- [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
- public string FileName;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
- public struct FILE_STREAM_INFO
- {
- public uint NextEntryOffset;
- public uint StreamNameLength;
- public long StreamSize;
- public long StreamAllocationSize;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
- public string StreamName;
- }
-
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public sealed class WIN32_FIND_STREAM_DATA
- {
- public long StreamSize;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 296)]
- public string cStreamName;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct SID_AND_ATTRIBUTES
- {
- public IntPtr Sid;
-
- public uint Attributes;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct SYSTEMTIME
- {
- [MarshalAs(UnmanagedType.U2)] public short Year;
- [MarshalAs(UnmanagedType.U2)] public short Month;
- [MarshalAs(UnmanagedType.U2)] public short DayOfWeek;
- [MarshalAs(UnmanagedType.U2)] public short Day;
- [MarshalAs(UnmanagedType.U2)] public short Hour;
- [MarshalAs(UnmanagedType.U2)] public short Minute;
- [MarshalAs(UnmanagedType.U2)] public short Second;
- [MarshalAs(UnmanagedType.U2)] public short Milliseconds;
-
- public SYSTEMTIME(DateTime dt)
- {
- dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC
- Year = (short)dt.Year;
- Month = (short)dt.Month;
- DayOfWeek = (short)dt.DayOfWeek;
- Day = (short)dt.Day;
- Hour = (short)dt.Hour;
- Minute = (short)dt.Minute;
- Second = (short)dt.Second;
- Milliseconds = (short)dt.Millisecond;
- }
-
- public DateTime ToDateTime()
- {
- return new(Year, Month, Day, Hour, Minute, Second, Milliseconds, DateTimeKind.Utc);
- }
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
- public struct WIN32_FIND_DATA
- {
- public uint dwFileAttributes;
-
- public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
- public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
- public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
-
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
- public string cFileName;
-
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CRYPTOAPI_BLOB
- {
- public uint cbData;
- public IntPtr pbData;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CMSG_SIGNER_INFO
- {
- public uint dwVersion;
- public CRYPTOAPI_BLOB Issuer;
- public CRYPTOAPI_BLOB SerialNumber;
- public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
- public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
- public CRYPTOAPI_BLOB EncryptedHash;
- public CRYPTOAPI_BLOB AuthAttrs;
- public CRYPTOAPI_BLOB UnauthAttrs;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct SignDataHandle
- {
- public uint dwObjSize;
- public IntPtr pSignerInfo;
- public IntPtr hCertStoreHandle;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CRYPT_ATTRIBUTE
- {
- [MarshalAs(UnmanagedType.LPStr)]
- public string pszObjId;
- public uint cValue;
- public IntPtr rgValue;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct FILETIME
- {
- public uint dwLowDateTime;
- public uint dwHighDateTime;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CRYPT_BIT_BLOB
- {
- private readonly uint cbData;
- private readonly IntPtr pbData;
- private readonly uint cUnusedBits;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CERT_ALT_NAME_INFO
- {
- public uint cAltEntry;
- public IntPtr rgAltEntry;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CERT_CONTEXT
- {
- public uint dwCertEncodingType;
- public IntPtr pbCertEncoded;
- public uint cbCertEncoded;
- public IntPtr pCertInfo;
- public IntPtr hCertStore;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CERT_INFO
- {
- public uint dwVersion;
- public CRYPTOAPI_BLOB SerialNumber;
- public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
- public CRYPTOAPI_BLOB Issuer;
- public FILETIME NotBefore;
- public FILETIME NotAfter;
- public CRYPTOAPI_BLOB Subject;
- public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
- public CRYPT_BIT_BLOB IssuerUniqueId;
- public CRYPT_BIT_BLOB SubjectUniqueId;
- public uint cExtension;
- public IntPtr rgExtension;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CRYPT_ALGORITHM_IDENTIFIER
- {
- [MarshalAs(UnmanagedType.LPStr)]
- public string pszObjId;
- public CRYPTOAPI_BLOB Parameters;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CERT_PUBLIC_KEY_INFO
- {
- public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
- public CRYPTOAPI_BLOB PublicKey;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CATALOG_INFO
- {
- public uint cbStruct;
- public char[] wszCatalogFile = new char[256];
-
- public CATALOG_INFO()
- {
- }
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct WINTRUST_FILE_INFO
- {
- public uint cbStruct;
- public IntPtr pcwszFilePath;
- public IntPtr hFile;
- public IntPtr pgKnownSubject;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct WINTRUST_DATA
- {
- public uint cbStruct;
- public IntPtr pPolicyCallbackData;
- public IntPtr pSIPClientData;
- public uint dwUIChoice;
- public uint fdwRevocationChecks;
- public uint dwUnionChoice;
- public IntPtr pFile;
- public uint dwStateAction;
- public IntPtr hVWTStateData;
- public IntPtr pwszURLReference;
- public uint dwProvFlags;
- public uint dwUIContext;
- public IntPtr pSignatureSettings;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
- public struct CRYPTUI_VIEWSIGNERINFO_STRUCT
- {
- public uint dwSize;
- public IntPtr hwndParent;
- public uint dwFlags;
- public IntPtr szTitle;
- public IntPtr pSignerInfo;
- public IntPtr hMsg;
- public IntPtr pszOID;
- public uint? dwReserved;
- public uint cStores;
- public IntPtr rghStores;
- public uint cPropPages;
- public IntPtr rgPropPages;
- }
- }
+ public static partial class Win32PInvoke
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RM_UNIQUE_PROCESS
+ {
+ public int dwProcessId;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct RM_PROCESS_INFO
+ {
+ public RM_UNIQUE_PROCESS Process;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
+ public string strAppName;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
+ public string strServiceShortName;
+
+ public RM_APP_TYPE ApplicationType;
+ public uint AppStatus;
+ public uint TSSessionId;
+ [MarshalAs(UnmanagedType.Bool)]
+ public bool bRestartable;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct BROWSEINFO
+ {
+ public IntPtr hwndOwner;
+ public IntPtr pidlRoot;
+ public string pszDisplayName;
+ public string lpszTitle;
+ public uint ulFlags;
+ public IntPtr lpfn;
+ public int lParam;
+ public IntPtr iImage;
+ }
+
+ public unsafe struct OVERLAPPED
+ {
+ public IntPtr Internal;
+ public IntPtr InternalHigh;
+ public Union PointerAndOffset;
+ public IntPtr hEvent;
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct Union
+ {
+ [FieldOffset(0)] public void* IntPtr;
+ [FieldOffset(0)] public OffsetPair Offset;
+
+ public struct OffsetPair { public uint Offset; public uint OffsetHigh; }
+ }
+ }
+
+ public unsafe struct FILE_NOTIFY_INFORMATION
+ {
+ public uint NextEntryOffset;
+ public uint Action;
+ public uint FileNameLength;
+ public fixed char FileName[1];
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct REPARSE_DATA_BUFFER
+ {
+ public uint ReparseTag;
+ public short ReparseDataLength;
+ public short Reserved;
+ public short SubsNameOffset;
+ public short SubsNameLength;
+ public short PrintNameOffset;
+ public short PrintNameLength;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_REPARSE_DATA_BUFFER_SIZE)]
+ public char[] PathBuffer;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WIN32_FILE_ATTRIBUTE_DATA
+ {
+ public FileAttributes dwFileAttributes;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct FILE_ID_BOTH_DIR_INFO
+ {
+ public uint NextEntryOffset;
+ public uint FileIndex;
+ public long CreationTime;
+ public long LastAccessTime;
+ public long LastWriteTime;
+ public long ChangeTime;
+ public long EndOfFile;
+ public long AllocationSize;
+ public uint FileAttributes;
+ public uint FileNameLength;
+ public uint EaSize;
+ public char ShortNameLength;
+ [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 12)]
+ public string ShortName;
+ public long FileId;
+ [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
+ public string FileName;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
+ public struct FILE_STREAM_INFO
+ {
+ public uint NextEntryOffset;
+ public uint StreamNameLength;
+ public long StreamSize;
+ public long StreamAllocationSize;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string StreamName;
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public sealed class WIN32_FIND_STREAM_DATA
+ {
+ public long StreamSize;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 296)]
+ public string cStreamName;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SID_AND_ATTRIBUTES
+ {
+ public IntPtr Sid;
+
+ public uint Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SYSTEMTIME
+ {
+ [MarshalAs(UnmanagedType.U2)] public short Year;
+ [MarshalAs(UnmanagedType.U2)] public short Month;
+ [MarshalAs(UnmanagedType.U2)] public short DayOfWeek;
+ [MarshalAs(UnmanagedType.U2)] public short Day;
+ [MarshalAs(UnmanagedType.U2)] public short Hour;
+ [MarshalAs(UnmanagedType.U2)] public short Minute;
+ [MarshalAs(UnmanagedType.U2)] public short Second;
+ [MarshalAs(UnmanagedType.U2)] public short Milliseconds;
+
+ public SYSTEMTIME(DateTime dt)
+ {
+ dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC
+ Year = (short)dt.Year;
+ Month = (short)dt.Month;
+ DayOfWeek = (short)dt.DayOfWeek;
+ Day = (short)dt.Day;
+ Hour = (short)dt.Hour;
+ Minute = (short)dt.Minute;
+ Second = (short)dt.Second;
+ Milliseconds = (short)dt.Millisecond;
+ }
+
+ public DateTime ToDateTime()
+ {
+ return new(Year, Month, Day, Hour, Minute, Second, Milliseconds, DateTimeKind.Utc);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct WIN32_FIND_DATA
+ {
+ public uint dwFileAttributes;
+
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
+
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string cFileName;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPTOAPI_BLOB
+ {
+ public uint cbData;
+ public IntPtr pbData;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CMSG_SIGNER_INFO
+ {
+ public uint dwVersion;
+ public CRYPTOAPI_BLOB Issuer;
+ public CRYPTOAPI_BLOB SerialNumber;
+ public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
+ public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
+ public CRYPTOAPI_BLOB EncryptedHash;
+ public CRYPTOAPI_BLOB AuthAttrs;
+ public CRYPTOAPI_BLOB UnauthAttrs;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SignDataHandle
+ {
+ public uint dwObjSize;
+ public IntPtr pSignerInfo;
+ public IntPtr hCertStoreHandle;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPT_ATTRIBUTE
+ {
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string pszObjId;
+ public uint cValue;
+ public IntPtr rgValue;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct FILETIME
+ {
+ public uint dwLowDateTime;
+ public uint dwHighDateTime;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPT_BIT_BLOB
+ {
+ private readonly uint cbData;
+ private readonly IntPtr pbData;
+ private readonly uint cUnusedBits;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_ALT_NAME_INFO
+ {
+ public uint cAltEntry;
+ public IntPtr rgAltEntry;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_CONTEXT
+ {
+ public uint dwCertEncodingType;
+ public IntPtr pbCertEncoded;
+ public uint cbCertEncoded;
+ public IntPtr pCertInfo;
+ public IntPtr hCertStore;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_INFO
+ {
+ public uint dwVersion;
+ public CRYPTOAPI_BLOB SerialNumber;
+ public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
+ public CRYPTOAPI_BLOB Issuer;
+ public FILETIME NotBefore;
+ public FILETIME NotAfter;
+ public CRYPTOAPI_BLOB Subject;
+ public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
+ public CRYPT_BIT_BLOB IssuerUniqueId;
+ public CRYPT_BIT_BLOB SubjectUniqueId;
+ public uint cExtension;
+ public IntPtr rgExtension;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPT_ALGORITHM_IDENTIFIER
+ {
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string pszObjId;
+ public CRYPTOAPI_BLOB Parameters;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_PUBLIC_KEY_INFO
+ {
+ public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
+ public CRYPTOAPI_BLOB PublicKey;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CATALOG_INFO
+ {
+ public uint cbStruct;
+ public char[] wszCatalogFile = new char[256];
+
+ public CATALOG_INFO()
+ {
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WINTRUST_FILE_INFO
+ {
+ public uint cbStruct;
+ public IntPtr pcwszFilePath;
+ public IntPtr hFile;
+ public IntPtr pgKnownSubject;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WINTRUST_DATA
+ {
+ public uint cbStruct;
+ public IntPtr pPolicyCallbackData;
+ public IntPtr pSIPClientData;
+ public uint dwUIChoice;
+ public uint fdwRevocationChecks;
+ public uint dwUnionChoice;
+ public IntPtr pFile;
+ public uint dwStateAction;
+ public IntPtr hVWTStateData;
+ public IntPtr pwszURLReference;
+ public uint dwProvFlags;
+ public uint dwUIContext;
+ public IntPtr pSignatureSettings;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct CRYPTUI_VIEWSIGNERINFO_STRUCT
+ {
+ public uint dwSize;
+ public IntPtr hwndParent;
+ public uint dwFlags;
+ public IntPtr szTitle;
+ public IntPtr pSignerInfo;
+ public IntPtr hMsg;
+ public IntPtr pszOID;
+ public uint? dwReserved;
+ public uint cStores;
+ public IntPtr rghStores;
+ public uint cPropPages;
+ public IntPtr rgPropPages;
+ }
+ }
}
diff --git a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
index 347dab0fa8bd..69ef278dbcb4 100644
--- a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
+++ b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
@@ -6,1036 +6,1036 @@
namespace Files.App.Utils.Signatures
{
- public static class DigitalSignaturesUtil
- {
- // OIDs
- private const string szOID_NESTED_SIGNATURE = "1.3.6.1.4.1.311.2.4.1";
- private const string szOID_RSA_counterSign = "1.2.840.113549.1.9.6";
- private const string szOID_RSA_signingTime = "1.2.840.113549.1.9.5";
- private const string szOID_RFC3161_counterSign = "1.3.6.1.4.1.311.3.3.1";
- private const string szOID_OIWSEC_sha1 = "1.3.14.3.2.26";
- private const string szOID_RSA_MD5 = "1.2.840.113549.2.5";
- private const string szOID_NIST_sha256 = "2.16.840.1.101.3.4.2.1";
-
- // Flags
- private const uint CERT_NAME_SIMPLE_DISPLAY_TYPE = 4;
- private const uint CERT_FIND_SUBJECT_NAME = 131079;
- private const uint CERT_FIND_ISSUER_NAME = 131076;
- private const uint CERT_QUERY_OBJECT_FILE = 0x00000001;
- private const uint CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = 0x00000400;
- private const uint CERT_QUERY_FORMAT_FLAG_BINARY = 0x00000002;
- private const uint CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000;
- private const IntPtr CERT_STORE_PROV_SYSTEM = 10;
- private const IntPtr CERT_STORE_PROV_MSG = 1;
-
- private const uint PKCS_7_ASN_ENCODING = 0x00010000;
- private const uint CRYPT_ASN_ENCODING = 0x00000001;
-
- private const IntPtr PKCS7_SIGNER_INFO = 500;
- private const IntPtr PKCS_UTC_TIME = 17;
-
- private const uint CMSG_SIGNER_INFO_PARAM = 6;
-
- // Version numbers
- private const uint CERT_V1 = 0;
- private const uint CERT_V2 = 1;
- private const uint CERT_V3 = 2;
-
- private static readonly byte[] SG_ProtoCoded = [
- 0x30, 0x82
- ];
-
- private static readonly byte[] SG_SignedData = [
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02
- ];
-
- private static readonly IDateTimeFormatter formatter = Ioc.Default.GetRequiredService();
-
- public static void LoadItemSignatures(
- string filePath,
- ObservableCollection signatures,
- IntPtr hWnd,
- CancellationToken ct)
- {
- var signChain = new List();
- GetSignerCertificateInfo(filePath, signChain, ct);
-
- foreach (var signNode in signChain)
- {
- if (signNode.CertChain.Count == 0)
- continue;
-
- var signatureInfo = new SignatureInfoItem(filePath, signNode.Index, hWnd, signNode.CertChain)
- {
- Version = signNode.Version,
- IssuedBy = signNode.CertChain[0].IssuedBy,
- IssuedTo = signNode.CertChain[0].IssuedTo,
- ValidFromTimestamp = signNode.CertChain[0].ValidFrom,
- ValidToTimestamp = signNode.CertChain[0].ValidTo,
- VerifiedTimestamp = signNode.CounterSign.TimeStamp,
- Verified = signNode.IsValid,
- };
- signatures.Add(signatureInfo);
- }
- }
-
- public static void DisplaySignerInfoDialog(string filePath, IntPtr hwndParent, int index)
- {
- if (string.IsNullOrEmpty(filePath))
- return;
-
- var hAuthCryptMsg = IntPtr.Zero;
- var signHandle = new SignDataHandle();
- var signDataChain = new List();
-
- try
- {
- var result = TryGetSignerInfo(
- filePath,
- ref hAuthCryptMsg,
- ref signHandle.hCertStoreHandle,
- ref signHandle.pSignerInfo,
- ref signHandle.dwObjSize
- );
- if (!result || signHandle.pSignerInfo == IntPtr.Zero)
- return;
-
- signDataChain.Add(signHandle);
- GetNestedSignerInfo(ref signHandle, signDataChain);
- if (index >= signDataChain.Count)
- return;
-
- signHandle = signDataChain[index];
- var signerInfo = Marshal.PtrToStructure(signHandle.pSignerInfo);
- var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(signerInfo.Issuer, pIssuer, false);
- var pCertContext = CertFindCertificateInStore(
- signHandle.hCertStoreHandle,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- 0,
- CERT_FIND_ISSUER_NAME,
- pIssuer,
- IntPtr.Zero
- );
- Marshal.FreeHGlobal(pIssuer);
- if (pCertContext == IntPtr.Zero)
- return;
-
- var viewInfo = new CRYPTUI_VIEWSIGNERINFO_STRUCT
- {
- dwSize = (uint)Marshal.SizeOf(),
- hwndParent = hwndParent,
- dwFlags = 0,
- szTitle = IntPtr.Zero,
- pSignerInfo = signHandle.pSignerInfo,
- hMsg = hAuthCryptMsg,
- pszOID = IntPtr.Zero,
- dwReserved = null,
- cStores = 1,
- rghStores = Marshal.AllocHGlobal(IntPtr.Size),
- cPropPages = 0,
- rgPropPages = IntPtr.Zero
- };
- Marshal.WriteIntPtr(viewInfo.rghStores, signHandle.hCertStoreHandle);
- var pViewInfo = Marshal.AllocHGlobal((int)viewInfo.dwSize);
- Marshal.StructureToPtr(viewInfo, pViewInfo, false);
-
- result = CryptUIDlgViewSignerInfo(pViewInfo);
-
- Marshal.FreeHGlobal(viewInfo.rghStores);
- Marshal.FreeHGlobal(pViewInfo);
- CertFreeCertificateContext(pCertContext);
- }
- finally
- {
- // Since signDataChain contains nested signatures,
- // you must release them starting from the last one.
- for (int i = signDataChain.Count - 1; i >= 0; i--)
- {
- if (signDataChain[i].pSignerInfo != IntPtr.Zero)
- Marshal.FreeHGlobal(signDataChain[i].pSignerInfo);
-
- if (signDataChain[i].hCertStoreHandle != IntPtr.Zero)
- CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
- }
-
- if (hAuthCryptMsg != IntPtr.Zero)
- CryptMsgClose(hAuthCryptMsg);
- }
- }
-
- private static bool GetSignerSignatureInfo(
- IntPtr hSystemStore,
- IntPtr hCertStore,
- IntPtr pOrigContext,
- ref IntPtr pCurrContext,
- SignNodeInfo signNode)
- {
- var currContext = Marshal.PtrToStructure(pCurrContext);
- var pCertInfo = currContext.pCertInfo;
- var certNode = new CertNodeInfoItem();
- var certInfo = Marshal.PtrToStructure(pCertInfo);
-
- (_, certNode.Version) = CalculateSignVersion(certInfo.dwVersion);
- GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, certNode);
- GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 1, certNode);
-
- var pft = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(certInfo.NotBefore, pft, false);
- certNode.ValidFrom = TimeToString(pft);
- Marshal.StructureToPtr(certInfo.NotAfter, pft, false);
- certNode.ValidTo = TimeToString(pft);
- Marshal.FreeHGlobal(pft);
-
- signNode.CertChain.Add(certNode);
-
- var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(certInfo.Issuer, pIssuer, false);
- pCurrContext = CertFindCertificateInStore(
- hCertStore,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- 0,
- CERT_FIND_SUBJECT_NAME,
- pIssuer,
- IntPtr.Zero
- );
-
- if (pCurrContext == IntPtr.Zero)
- {
- pCurrContext = CertFindCertificateInStore(
- hSystemStore,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- 0,
- CERT_FIND_SUBJECT_NAME,
- pIssuer,
- IntPtr.Zero
- );
- }
-
- Marshal.FreeHGlobal(pIssuer);
- if (pCurrContext == IntPtr.Zero)
- return false;
-
- var pCurrPublicKey = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(certInfo.SubjectPublicKeyInfo, pCurrPublicKey, false);
-
- var origContext = Marshal.PtrToStructure(pOrigContext);
- var origInfo = Marshal.PtrToStructure(origContext.pCertInfo);
- var pOrigPublicKey = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(origInfo.SubjectPublicKeyInfo, pOrigPublicKey, false);
-
- var result = CertComparePublicKeyInfo(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- pCurrPublicKey,
- pOrigPublicKey
- );
-
- Marshal.FreeHGlobal(pCurrPublicKey);
- Marshal.FreeHGlobal(pOrigPublicKey);
-
- return !result;
- }
-
- private static bool GetSignerCertificateInfo(string fileName, List signChain, CancellationToken ct)
- {
- var succeded = false;
- var authSignData = new SignDataHandle();
- var signDataChain = new List();
- signChain.Clear();
-
- var pRoot = Marshal.StringToHGlobalAuto("Root");
- var hSystemStore = CertOpenStore(
- CERT_STORE_PROV_SYSTEM,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- IntPtr.Zero,
- CERT_SYSTEM_STORE_CURRENT_USER,
- pRoot
- );
- Marshal.FreeHGlobal(pRoot);
- if (hSystemStore == IntPtr.Zero)
- return false;
-
- var hAuthCryptMsg = IntPtr.Zero;
- var result = TryGetSignerInfo(
- fileName,
- ref hAuthCryptMsg,
- ref authSignData.hCertStoreHandle,
- ref authSignData.pSignerInfo,
- ref authSignData.dwObjSize
- );
-
- if (hAuthCryptMsg != IntPtr.Zero)
- {
- CryptMsgClose(hAuthCryptMsg);
- hAuthCryptMsg = IntPtr.Zero;
- }
-
- if (!result)
- {
- if (authSignData.hCertStoreHandle != IntPtr.Zero)
- CertCloseStore(authSignData.hCertStoreHandle, 0);
-
- CertCloseStore(hSystemStore, 0);
- return false;
- }
-
- signDataChain.Add(authSignData);
- GetNestedSignerInfo(ref authSignData, signDataChain);
-
- for (var i = 0; i < signDataChain.Count; i++)
- {
- if (ct.IsCancellationRequested)
- {
- CertCloseStore(hSystemStore, 0);
- return false;
- }
-
- var pCurrContext = IntPtr.Zero;
- var pCounterSigner = IntPtr.Zero;
- var signNode = new SignNodeInfo();
-
- GetCounterSignerInfo(signDataChain[i].pSignerInfo, ref pCounterSigner);
- if (pCounterSigner != IntPtr.Zero)
- GetCounterSignerData(pCounterSigner, signNode.CounterSign);
- else
- GetGeneralizedTimeStamp(signDataChain[i].pSignerInfo, signNode.CounterSign);
-
- var signerInfo = Marshal.PtrToStructure(signDataChain[i].pSignerInfo);
- var szObjId = signerInfo.HashAlgorithm.pszObjId;
- CalculateDigestAlgorithm(szObjId, signNode);
- (_, signNode.Version) = CalculateSignVersion(signerInfo.dwVersion);
-
- var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(signerInfo.Issuer, pIssuer, false);
- pCurrContext = CertFindCertificateInStore(
- signDataChain[i].hCertStoreHandle,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- 0,
- CERT_FIND_ISSUER_NAME,
- pIssuer,
- IntPtr.Zero
- );
- Marshal.FreeHGlobal(pIssuer);
-
- result = pCurrContext != IntPtr.Zero;
- while (result)
- {
- var pOrigContext = pCurrContext;
- result = GetSignerSignatureInfo(
- hSystemStore,
- signDataChain[i].hCertStoreHandle,
- pOrigContext,
- ref pCurrContext,
- signNode
- );
- CertFreeCertificateContext(pOrigContext);
- }
-
- if (pCurrContext != IntPtr.Zero)
- CertFreeCertificateContext(pCurrContext);
-
- if (pCounterSigner != IntPtr.Zero)
- Marshal.FreeHGlobal(pCounterSigner);
-
- if (signDataChain[i].pSignerInfo != IntPtr.Zero)
- Marshal.FreeHGlobal(signDataChain[i].pSignerInfo);
-
- if (signDataChain[i].hCertStoreHandle != IntPtr.Zero)
- CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
-
- succeded = true;
- signNode.IsValid = VerifyySignature(fileName);
- signNode.Index = i;
- signChain.Add(signNode);
- }
-
- CertCloseStore(hSystemStore, 0);
- return succeded;
- }
-
- private static bool VerifyySignature(string certPath)
- {
- var actionGuid = new Guid("{00AAC56B-CD44-11D0-8CC2-00C04FC295EE}");
- var guidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(actionGuid));
- Marshal.StructureToPtr(actionGuid, guidPtr, false);
-
- var sFileInfo = Marshal.SizeOf();
- var fileInfo = new WINTRUST_FILE_INFO
- {
- cbStruct = (uint)sFileInfo,
- pcwszFilePath = Marshal.StringToCoTaskMemAuto(certPath),
- hFile = IntPtr.Zero,
- pgKnownSubject = IntPtr.Zero
- };
- var filePtr = Marshal.AllocHGlobal(sFileInfo);
- Marshal.StructureToPtr(fileInfo, filePtr, false);
-
- var sData = Marshal.SizeOf();
- var wintrustData = new WINTRUST_DATA
- {
- cbStruct = (uint)sData,
- pPolicyCallbackData = IntPtr.Zero,
- pSIPClientData = IntPtr.Zero,
- dwUIChoice = 2, // Display no UI
- fdwRevocationChecks = 0, // No revocation checking
- dwUnionChoice = 1, // Verify an embedded signature on a file
- dwStateAction = 1, // Verify action
- hVWTStateData = IntPtr.Zero,
- pwszURLReference = IntPtr.Zero,
- dwUIContext = 0,
- pFile = filePtr
- };
- var dataPtr = Marshal.AllocHGlobal(sData);
- Marshal.StructureToPtr(wintrustData, dataPtr, false);
-
- try
- {
- var res = WinVerifyTrust(IntPtr.Zero, guidPtr, dataPtr);
-
- // Release hWVTStateData
- wintrustData.dwStateAction = 2; // Close
- Marshal.StructureToPtr(wintrustData, dataPtr, true);
- WinVerifyTrust(IntPtr.Zero, guidPtr, dataPtr);
-
- return res == 0;
- }
- finally
- {
- if (fileInfo.pcwszFilePath != IntPtr.Zero)
- Marshal.FreeCoTaskMem(fileInfo.pcwszFilePath);
-
- Marshal.FreeHGlobal(guidPtr);
- Marshal.FreeHGlobal(filePtr);
- Marshal.FreeHGlobal(dataPtr);
- }
- }
-
- private static bool TryGetSignerInfo(
- string fileName,
- ref IntPtr hMsg,
- ref IntPtr hCertStore,
- ref IntPtr pSignerInfo,
- ref uint signerSize,
- uint index = 0)
- {
- uint encoding = 0;
- var pDummy = IntPtr.Zero;
- uint dummy = 0;
- var pFileName = Marshal.StringToHGlobalAuto(fileName);
- var result = CryptQueryObject(
- CERT_QUERY_OBJECT_FILE,
- pFileName,
- CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
- CERT_QUERY_FORMAT_FLAG_BINARY,
- 0,
- ref encoding,
- ref dummy,
- ref dummy,
- ref hCertStore,
- ref hMsg,
- ref pDummy
- );
- Marshal.FreeHGlobal(pFileName);
-
- if (!result)
- return false;
-
- result = CustomCryptMsgGetParam(
- hMsg,
- CMSG_SIGNER_INFO_PARAM,
- index,
- ref pSignerInfo,
- ref signerSize
- );
-
- return result;
- }
-
- private static bool GetCounterSignerInfo(IntPtr pSignerInfo, ref IntPtr pTargetSigner)
- {
- uint objSize = 0;
- if (pSignerInfo == IntPtr.Zero)
- return false;
-
- try
- {
- var res = TryGetUnauthAttr(pSignerInfo, szOID_RSA_counterSign, out var attr);
- if (!res)
- return false;
-
- var rgValue = Marshal.PtrToStructure(attr.rgValue);
- var result = CryptDecodeObject(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- PKCS7_SIGNER_INFO,
- rgValue.pbData,
- rgValue.cbData,
- 0,
- IntPtr.Zero,
- ref objSize
- );
- if (!result)
- return false;
-
- pTargetSigner = Marshal.AllocHGlobal((int)objSize * sizeof(byte));
- if (pTargetSigner == IntPtr.Zero)
- return false;
-
- result = CryptDecodeObject(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- PKCS7_SIGNER_INFO,
- rgValue.pbData,
- rgValue.cbData,
- 0,
- pTargetSigner,
- ref objSize
- );
- if (!result)
- return false;
- }
- finally
- {
- }
-
- return true;
- }
-
- private static bool GetCounterSignerData(IntPtr pSignerInfo, SignCounterSign counterSign)
- {
- var res = TryGetAuthAttr(pSignerInfo, szOID_RSA_signingTime, out var attr);
- if (!res)
- return false;
-
- var rgValue = Marshal.PtrToStructure(attr.rgValue);
-
- var data = (uint)Marshal.SizeOf();
- var ft = Marshal.AllocHGlobal((int)data);
- IntPtr lft = IntPtr.Zero;
- IntPtr st = IntPtr.Zero;
-
- try
- {
- var pStructType = Marshal.StringToHGlobalUni(szOID_RSA_signingTime);
- var result = CryptDecodeObject(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- PKCS_UTC_TIME,
- rgValue.pbData,
- rgValue.cbData,
- 0,
- ft,
- ref data
- );
- Marshal.FreeHGlobal(pStructType);
- if (!result)
- return false;
-
- lft = Marshal.AllocHGlobal((int)data);
- st = Marshal.AllocHGlobal(Marshal.SizeOf());
- FileTimeToLocalFileTime(ft, lft);
- FileTimeToSystemTime(lft, st);
- counterSign.TimeStamp = TimeToString(IntPtr.Zero, st);
-
- return true;
- }
- finally
- {
- Marshal.FreeHGlobal(ft);
- if (lft != IntPtr.Zero)
- Marshal.FreeHGlobal(lft);
-
- if (st != IntPtr.Zero)
- Marshal.FreeHGlobal(st);
- }
- }
-
- private static bool ParseDERFindType(
- int typeSearch,
- IntPtr pbSignature,
- uint size,
- ref uint positionFound,
- ref uint lengthFound)
- {
- uint position = 0;
- uint sizeFound = 0;
- uint bytesParsed = 0;
- var iType = 0;
- var iClass = 0;
- positionFound = 0;
- lengthFound = 0;
- if (pbSignature == IntPtr.Zero)
- return false;
-
- while (size > position)
- {
- if (!SafeToReadNBytes(size, position, 2))
- return false;
-
- ParseDERType(Marshal.ReadByte(pbSignature, (int)position), ref iType, ref iClass);
- switch (iType)
- {
- case 0x05: // Null
- ++position;
- if (Marshal.ReadByte(pbSignature, (int)position) != 0x00)
- return false;
-
- ++position;
- break;
-
- case 0x06: // Object Identifier
- ++position;
- var val = Marshal.ReadByte(pbSignature, (int)position);
- if (!SafeToReadNBytes(size - position, 1, val))
- return false;
-
- position += 1u + val;
- break;
-
- case 0x00: // ?
- case 0x01: // Boolean
- case 0x02: // Integer
- case 0x03: // Bit String
- case 0x04: // Octet String
- case 0x0A: // enumerated
- case 0x0C: // UTF8string
- case 0x13: // printable string
- case 0x14: // T61 string
- case 0x16: // IA5String
- case 0x17: // UTC time
- case 0x18: // Generalized time
- case 0x1E: // BMPstring
- ++position;
- if (!ParseDERSize(
- IntPtr.Add(pbSignature, (int)position),
- size - position,
- ref sizeFound,
- ref bytesParsed))
- {
- return false;
- }
-
- position += bytesParsed;
- if (!SafeToReadNBytes(size - position, 0, sizeFound))
- return false;
-
- if (typeSearch == iType)
- {
- positionFound = position;
- lengthFound = sizeFound;
-
- return true;
- }
-
- position += sizeFound;
- break;
-
- case 0x20: // context specific
- case 0x21: // context specific
- case 0x23: // context specific
- case 0x24: // context specific
- case 0x30: // sequence
- case 0x31: // set
- position++;
- if (!ParseDERSize(
- IntPtr.Add(pbSignature, (int)position),
- size - position,
- ref sizeFound,
- ref bytesParsed))
- {
- return false;
- }
-
- position += bytesParsed;
- break;
-
- case 0x22: // ?
- position += 2;
- break;
-
- default:
- return false;
- }
- }
-
- return false;
- }
-
- private static bool GetGeneralizedTimeStamp(
- IntPtr pSignerInfo,
- SignCounterSign counter)
- {
- uint positionFound = 0;
- uint lengthFound = 0;
- var res = TryGetUnauthAttr(pSignerInfo, szOID_RFC3161_counterSign, out var attr);
- if (!res)
- return false;
-
- var rgValue = Marshal.PtrToStructure(attr.rgValue);
- var result = ParseDERFindType(
- 0x04,
- rgValue.pbData,
- rgValue.cbData,
- ref positionFound,
- ref lengthFound);
- if (!result)
- return false;
-
- // Counter Signer Timstamp
- var pbOctetString = IntPtr.Add(rgValue.pbData, (int)positionFound);
- counter.TimeStamp = GetTimeStampFromDER(pbOctetString, lengthFound, ref positionFound);
-
- return true;
- }
-
- private static string GetTimeStampFromDER(IntPtr pbOctetString, uint lengthFound, ref uint positionFound)
- {
- var result = ParseDERFindType(
- 0x18,
- pbOctetString,
- lengthFound,
- ref positionFound,
- ref lengthFound
- );
- if (!result)
- return string.Empty;
-
- var st = new SYSTEMTIME();
- var buffer = Marshal.PtrToStringUTF8(
- IntPtr.Add(pbOctetString, (int)positionFound),
- (int)lengthFound
- ) + (char)0;
-
- _ = short.TryParse(buffer.AsSpan(0, 4), out st.Year);
- _ = short.TryParse(buffer.AsSpan(4, 2), out st.Month);
- _ = short.TryParse(buffer.AsSpan(6, 2), out st.Day);
- _ = short.TryParse(buffer.AsSpan(8, 2), out st.Hour);
- _ = short.TryParse(buffer.AsSpan(10, 2), out st.Minute);
- _ = short.TryParse(buffer.AsSpan(12, 2), out st.Second);
- _ = short.TryParse(buffer.AsSpan(15, 3), out st.Milliseconds);
-
- var sst = Marshal.AllocHGlobal(Marshal.SizeOf());
- var lst = Marshal.AllocHGlobal(Marshal.SizeOf());
- var fft = Marshal.AllocHGlobal(Marshal.SizeOf());
- var lft = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(st, sst, true);
- SystemTimeToFileTime(sst, fft);
- FileTimeToLocalFileTime(fft, lft);
- FileTimeToSystemTime(lft, lst);
- var timestamp = TimeToString(IntPtr.Zero, lst);
-
- Marshal.FreeHGlobal(fft);
- Marshal.FreeHGlobal(lft);
- Marshal.FreeHGlobal(sst);
- Marshal.FreeHGlobal(lst);
-
- return timestamp;
- }
-
- private static bool GetStringFromCertContext(IntPtr pCertContext, uint dwType, uint flag, CertNodeInfoItem info)
- {
- var data = CertGetNameStringA(pCertContext, dwType, flag, IntPtr.Zero, IntPtr.Zero, 0);
- if (data == 0)
- {
- CertFreeCertificateContext(pCertContext);
- return false;
- }
-
- var pszTempName = Marshal.AllocHGlobal((int)data * sizeof(byte));
- if (pszTempName == IntPtr.Zero)
- {
- CertFreeCertificateContext(pCertContext);
- return false;
- }
-
- data = CertGetNameStringA(pCertContext, dwType, flag, IntPtr.Zero, pszTempName, data);
- if (data == 0)
- {
- Marshal.FreeHGlobal(pszTempName);
- return false;
- }
-
- if (flag == 0)
- info.IssuedTo = StripString(Marshal.PtrToStringUTF8(pszTempName));
- else
- info.IssuedBy = StripString(Marshal.PtrToStringUTF8(pszTempName));
-
- Marshal.FreeHGlobal(pszTempName);
-
- return true;
- }
-
- private static bool TryGetUnauthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
- {
- int n = 0;
- var signerInfo = Marshal.PtrToStructure(pSignerInfo);
- attr = new CRYPT_ATTRIBUTE();
- for (; n < signerInfo.UnauthAttrs.cbData; n++)
- {
- attr = Marshal.PtrToStructure(
- IntPtr.Add(signerInfo.UnauthAttrs.pbData, n * Marshal.SizeOf())
- );
- if (attr.pszObjId == oid)
- break;
- }
-
- return n < signerInfo.UnauthAttrs.cbData;
- }
-
- private static bool TryGetAuthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
- {
- int n = 0;
- var signerInfo = Marshal.PtrToStructure(pSignerInfo);
- attr = new CRYPT_ATTRIBUTE();
- for (; n < signerInfo.AuthAttrs.cbData; n++)
- {
- attr = Marshal.PtrToStructure(
- IntPtr.Add(signerInfo.AuthAttrs.pbData, n * Marshal.SizeOf())
- );
- if (attr.pszObjId == oid)
- break;
- }
-
- return n < signerInfo.AuthAttrs.cbData;
- }
-
- private static bool GetNestedSignerInfo(ref SignDataHandle AuthSignData, List NestedChain)
- {
- var succeded = false;
- var hNestedMsg = IntPtr.Zero;
- if (AuthSignData.pSignerInfo == IntPtr.Zero)
- return false;
-
- try
- {
- var res = TryGetUnauthAttr(AuthSignData.pSignerInfo, szOID_NESTED_SIGNATURE, out var attr);
- if (!res)
- return false;
-
- var rgValue = Marshal.PtrToStructure(attr.rgValue);
- var cbCurrData = rgValue.cbData;
- var pbCurrData = rgValue.pbData;
-
- var upperBound = IntPtr.Add(AuthSignData.pSignerInfo, (int)AuthSignData.dwObjSize);
- while (pbCurrData > AuthSignData.pSignerInfo && pbCurrData < upperBound)
- {
- var nestedHandle = new SignDataHandle() { dwObjSize = 0 };
- if (!Memcmp(pbCurrData, SG_ProtoCoded) ||
- !Memcmp(IntPtr.Add(pbCurrData, 6), SG_SignedData))
- {
- break;
- }
-
- hNestedMsg = CryptMsgOpenToDecode(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- 0,
- 0,
- IntPtr.Zero,
- IntPtr.Zero,
- IntPtr.Zero
- );
- if (hNestedMsg == IntPtr.Zero)
- return false;
-
- cbCurrData = XCHWordLitend(unchecked((ushort)Marshal.ReadInt16(pbCurrData)) + 2u) + 4u;
- var pbNextData = pbCurrData;
- pbNextData = IntPtr.Add(pbNextData, (int)EightByteAlign(cbCurrData, unchecked(pbCurrData)));
- var result = CryptMsgUpdate(hNestedMsg, pbCurrData, cbCurrData, true);
- pbCurrData = pbNextData;
- if (!result)
- continue;
-
- result = CustomCryptMsgGetParam(
- hNestedMsg,
- CMSG_SIGNER_INFO_PARAM,
- 0,
- ref nestedHandle.pSignerInfo,
- ref nestedHandle.dwObjSize
- );
- if (!result)
- continue;
-
- nestedHandle.hCertStoreHandle = CertOpenStore(
- CERT_STORE_PROV_MSG,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- IntPtr.Zero,
- 0,
- hNestedMsg
- );
-
- succeded = true;
- NestedChain.Add(nestedHandle);
- }
- }
- finally
- {
- if (hNestedMsg != IntPtr.Zero)
- CryptMsgClose(hNestedMsg);
- }
-
- return succeded;
- }
-
- private static bool CustomCryptMsgGetParam(
- IntPtr hCryptMsg,
- uint paramType,
- uint index,
- ref IntPtr pParam,
- ref uint outSize)
- {
- bool result;
- uint size = 0;
-
- result = CryptMsgGetParam(
- hCryptMsg,
- paramType,
- index,
- IntPtr.Zero,
- ref size
- );
- if (!result)
- return false;
-
- pParam = Marshal.AllocHGlobal((int)size);
- if (pParam == IntPtr.Zero)
- return false;
-
- result = CryptMsgGetParam(
- hCryptMsg,
- paramType,
- index,
- pParam,
- ref size
- );
- if (!result)
- return false;
-
- outSize = size;
- return true;
- }
-
- private static ushort XCHWordLitend(uint num)
- => (ushort)(((((ushort)num) & 0xFF00) >> 8) | (((ushort)num) & 0x00FF) << 8);
-
- private static long EightByteAlign(long offset, long b)
- => ((offset + b + 7) & 0xFFFFFFF8L) - (b & 0xFFFFFFF8L);
-
- private static bool Memcmp(IntPtr ptr1, byte[] arr)
- {
- for (var i = 0; i < arr.Length; i++)
- {
- if (Marshal.ReadByte(ptr1, i) != arr[i])
- return false;
- }
-
- return true;
- }
-
- private static (bool, string) CalculateSignVersion(uint versionNumber)
- {
- var res = versionNumber switch
- {
- CERT_V1 => "V1",
- CERT_V2 => "V2",
- CERT_V3 => "V3",
- _ => "Unknown",
- };
- return (true, res);
- }
-
- private static bool CalculateDigestAlgorithm(string pszObjId, SignNodeInfo info)
- {
- if (string.IsNullOrWhiteSpace(pszObjId))
- info.DigestAlgorithm = "Unknown";
- else if (pszObjId == szOID_OIWSEC_sha1)
- info.DigestAlgorithm = "SHA1";
- else if (pszObjId == szOID_RSA_MD5)
- info.DigestAlgorithm = "MD5";
- else if (pszObjId == szOID_NIST_sha256)
- info.DigestAlgorithm = "SHA256";
- else
- info.DigestAlgorithm = StripString(pszObjId);
-
- return true;
- }
-
- private static bool SafeToReadNBytes(uint size, uint start, uint requestSize)
- => size - start >= requestSize;
-
- private static void ParseDERType(byte bIn, ref int iType, ref int iClass)
- {
- iType = bIn & 0x3F;
- iClass = bIn >> 6;
- }
-
- private static uint ReadNumberFromNBytes(IntPtr pbSignature, uint start, uint requestSize)
- {
- uint number = 0;
- for (var i = 0; i < requestSize; i++)
- number = number * 0x100 + Marshal.ReadByte(pbSignature, (int)(start + i));
-
- return number;
- }
-
- private static bool ParseDERSize(IntPtr pbSignature, uint size, ref uint sizeFound, ref uint bytesParsed)
- {
- var val = Marshal.ReadByte(pbSignature);
- if (val > 0x80 && !SafeToReadNBytes(size, 1, val - 0x80u))
- return false;
-
- if (val <= 0x80)
- {
- sizeFound = val;
- bytesParsed = 1;
- }
- else
- {
- sizeFound = ReadNumberFromNBytes(pbSignature, 1, val - 0x80u);
- bytesParsed = val - 0x80u + 1;
- }
-
- return true;
- }
-
- private static string StripString(string? str)
- {
- return str?
- .Replace("\t", "")?
- .Replace("\n", "")?
- .Replace("\r", "")?
- .Replace(((char)0).ToString(), "") ?? string.Empty;
- }
-
- private static string TimeToString(IntPtr pftIn, IntPtr pstIn = 0)
- {
- if (pstIn == IntPtr.Zero)
- {
- if (pftIn == IntPtr.Zero)
- return string.Empty;
-
- pstIn = Marshal.AllocHGlobal(Marshal.SizeOf());
- FileTimeToSystemTime(pftIn, pstIn);
- }
-
- var st = Marshal.PtrToStructure(pstIn);
- var date = new DateTime(
- st.Year, st.Month, st.Day,
- st.Hour, st.Minute, st.Second
- );
-
- return formatter.ToLongLabel(date);
- }
-
- class SignCounterSign
- {
- public string TimeStamp { get; set; } = string.Empty;
- }
-
- class SignNodeInfo
- {
- public bool IsValid { get; set; } = false;
- public string DigestAlgorithm { get; set; } = string.Empty;
- public string Version { get; set; } = string.Empty;
- public int Index { get; set; } = 0;
- public SignCounterSign CounterSign { get; set; } = new();
- public List CertChain = [];
- }
- }
+ public static class DigitalSignaturesUtil
+ {
+ // OIDs
+ private const string szOID_NESTED_SIGNATURE = "1.3.6.1.4.1.311.2.4.1";
+ private const string szOID_RSA_counterSign = "1.2.840.113549.1.9.6";
+ private const string szOID_RSA_signingTime = "1.2.840.113549.1.9.5";
+ private const string szOID_RFC3161_counterSign = "1.3.6.1.4.1.311.3.3.1";
+ private const string szOID_OIWSEC_sha1 = "1.3.14.3.2.26";
+ private const string szOID_RSA_MD5 = "1.2.840.113549.2.5";
+ private const string szOID_NIST_sha256 = "2.16.840.1.101.3.4.2.1";
+
+ // Flags
+ private const uint CERT_NAME_SIMPLE_DISPLAY_TYPE = 4;
+ private const uint CERT_FIND_SUBJECT_NAME = 131079;
+ private const uint CERT_FIND_ISSUER_NAME = 131076;
+ private const uint CERT_QUERY_OBJECT_FILE = 0x00000001;
+ private const uint CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = 0x00000400;
+ private const uint CERT_QUERY_FORMAT_FLAG_BINARY = 0x00000002;
+ private const uint CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000;
+ private const IntPtr CERT_STORE_PROV_SYSTEM = 10;
+ private const IntPtr CERT_STORE_PROV_MSG = 1;
+
+ private const uint PKCS_7_ASN_ENCODING = 0x00010000;
+ private const uint CRYPT_ASN_ENCODING = 0x00000001;
+
+ private const IntPtr PKCS7_SIGNER_INFO = 500;
+ private const IntPtr PKCS_UTC_TIME = 17;
+
+ private const uint CMSG_SIGNER_INFO_PARAM = 6;
+
+ // Version numbers
+ private const uint CERT_V1 = 0;
+ private const uint CERT_V2 = 1;
+ private const uint CERT_V3 = 2;
+
+ private static readonly byte[] SG_ProtoCoded = [
+ 0x30, 0x82
+ ];
+
+ private static readonly byte[] SG_SignedData = [
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02
+ ];
+
+ private static readonly IDateTimeFormatter formatter = Ioc.Default.GetRequiredService();
+
+ public static void LoadItemSignatures(
+ string filePath,
+ ObservableCollection signatures,
+ IntPtr hWnd,
+ CancellationToken ct)
+ {
+ var signChain = new List();
+ GetSignerCertificateInfo(filePath, signChain, ct);
+
+ foreach (var signNode in signChain)
+ {
+ if (signNode.CertChain.Count == 0)
+ continue;
+
+ var signatureInfo = new SignatureInfoItem(filePath, signNode.Index, hWnd, signNode.CertChain)
+ {
+ Version = signNode.Version,
+ IssuedBy = signNode.CertChain[0].IssuedBy,
+ IssuedTo = signNode.CertChain[0].IssuedTo,
+ ValidFromTimestamp = signNode.CertChain[0].ValidFrom,
+ ValidToTimestamp = signNode.CertChain[0].ValidTo,
+ VerifiedTimestamp = signNode.CounterSign.TimeStamp,
+ Verified = signNode.IsValid,
+ };
+ signatures.Add(signatureInfo);
+ }
+ }
+
+ public static void DisplaySignerInfoDialog(string filePath, IntPtr hwndParent, int index)
+ {
+ if (string.IsNullOrEmpty(filePath))
+ return;
+
+ var hAuthCryptMsg = IntPtr.Zero;
+ var signHandle = new SignDataHandle();
+ var signDataChain = new List();
+
+ try
+ {
+ var result = TryGetSignerInfo(
+ filePath,
+ ref hAuthCryptMsg,
+ ref signHandle.hCertStoreHandle,
+ ref signHandle.pSignerInfo,
+ ref signHandle.dwObjSize
+ );
+ if (!result || signHandle.pSignerInfo == IntPtr.Zero)
+ return;
+
+ signDataChain.Add(signHandle);
+ GetNestedSignerInfo(ref signHandle, signDataChain);
+ if (index >= signDataChain.Count)
+ return;
+
+ signHandle = signDataChain[index];
+ var signerInfo = Marshal.PtrToStructure(signHandle.pSignerInfo);
+ var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(signerInfo.Issuer, pIssuer, false);
+ var pCertContext = CertFindCertificateInStore(
+ signHandle.hCertStoreHandle,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ CERT_FIND_ISSUER_NAME,
+ pIssuer,
+ IntPtr.Zero
+ );
+ Marshal.FreeHGlobal(pIssuer);
+ if (pCertContext == IntPtr.Zero)
+ return;
+
+ var viewInfo = new CRYPTUI_VIEWSIGNERINFO_STRUCT
+ {
+ dwSize = (uint)Marshal.SizeOf(),
+ hwndParent = hwndParent,
+ dwFlags = 0,
+ szTitle = IntPtr.Zero,
+ pSignerInfo = signHandle.pSignerInfo,
+ hMsg = hAuthCryptMsg,
+ pszOID = IntPtr.Zero,
+ dwReserved = null,
+ cStores = 1,
+ rghStores = Marshal.AllocHGlobal(IntPtr.Size),
+ cPropPages = 0,
+ rgPropPages = IntPtr.Zero
+ };
+ Marshal.WriteIntPtr(viewInfo.rghStores, signHandle.hCertStoreHandle);
+ var pViewInfo = Marshal.AllocHGlobal((int)viewInfo.dwSize);
+ Marshal.StructureToPtr(viewInfo, pViewInfo, false);
+
+ result = CryptUIDlgViewSignerInfo(pViewInfo);
+
+ Marshal.FreeHGlobal(viewInfo.rghStores);
+ Marshal.FreeHGlobal(pViewInfo);
+ CertFreeCertificateContext(pCertContext);
+ }
+ finally
+ {
+ // Since signDataChain contains nested signatures,
+ // you must release them starting from the last one.
+ for (int i = signDataChain.Count - 1; i >= 0; i--)
+ {
+ if (signDataChain[i].pSignerInfo != IntPtr.Zero)
+ Marshal.FreeHGlobal(signDataChain[i].pSignerInfo);
+
+ if (signDataChain[i].hCertStoreHandle != IntPtr.Zero)
+ CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
+ }
+
+ if (hAuthCryptMsg != IntPtr.Zero)
+ CryptMsgClose(hAuthCryptMsg);
+ }
+ }
+
+ private static bool GetSignerSignatureInfo(
+ IntPtr hSystemStore,
+ IntPtr hCertStore,
+ IntPtr pOrigContext,
+ ref IntPtr pCurrContext,
+ SignNodeInfo signNode)
+ {
+ var currContext = Marshal.PtrToStructure(pCurrContext);
+ var pCertInfo = currContext.pCertInfo;
+ var certNode = new CertNodeInfoItem();
+ var certInfo = Marshal.PtrToStructure(pCertInfo);
+
+ (_, certNode.Version) = CalculateSignVersion(certInfo.dwVersion);
+ GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, certNode);
+ GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 1, certNode);
+
+ var pft = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(certInfo.NotBefore, pft, false);
+ certNode.ValidFrom = TimeToString(pft);
+ Marshal.StructureToPtr(certInfo.NotAfter, pft, false);
+ certNode.ValidTo = TimeToString(pft);
+ Marshal.FreeHGlobal(pft);
+
+ signNode.CertChain.Add(certNode);
+
+ var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(certInfo.Issuer, pIssuer, false);
+ pCurrContext = CertFindCertificateInStore(
+ hCertStore,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ pIssuer,
+ IntPtr.Zero
+ );
+
+ if (pCurrContext == IntPtr.Zero)
+ {
+ pCurrContext = CertFindCertificateInStore(
+ hSystemStore,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ pIssuer,
+ IntPtr.Zero
+ );
+ }
+
+ Marshal.FreeHGlobal(pIssuer);
+ if (pCurrContext == IntPtr.Zero)
+ return false;
+
+ var pCurrPublicKey = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(certInfo.SubjectPublicKeyInfo, pCurrPublicKey, false);
+
+ var origContext = Marshal.PtrToStructure(pOrigContext);
+ var origInfo = Marshal.PtrToStructure(origContext.pCertInfo);
+ var pOrigPublicKey = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(origInfo.SubjectPublicKeyInfo, pOrigPublicKey, false);
+
+ var result = CertComparePublicKeyInfo(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ pCurrPublicKey,
+ pOrigPublicKey
+ );
+
+ Marshal.FreeHGlobal(pCurrPublicKey);
+ Marshal.FreeHGlobal(pOrigPublicKey);
+
+ return !result;
+ }
+
+ private static bool GetSignerCertificateInfo(string fileName, List signChain, CancellationToken ct)
+ {
+ var succeded = false;
+ var authSignData = new SignDataHandle();
+ var signDataChain = new List();
+ signChain.Clear();
+
+ var pRoot = Marshal.StringToHGlobalAuto("Root");
+ var hSystemStore = CertOpenStore(
+ CERT_STORE_PROV_SYSTEM,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ IntPtr.Zero,
+ CERT_SYSTEM_STORE_CURRENT_USER,
+ pRoot
+ );
+ Marshal.FreeHGlobal(pRoot);
+ if (hSystemStore == IntPtr.Zero)
+ return false;
+
+ var hAuthCryptMsg = IntPtr.Zero;
+ var result = TryGetSignerInfo(
+ fileName,
+ ref hAuthCryptMsg,
+ ref authSignData.hCertStoreHandle,
+ ref authSignData.pSignerInfo,
+ ref authSignData.dwObjSize
+ );
+
+ if (hAuthCryptMsg != IntPtr.Zero)
+ {
+ CryptMsgClose(hAuthCryptMsg);
+ hAuthCryptMsg = IntPtr.Zero;
+ }
+
+ if (!result)
+ {
+ if (authSignData.hCertStoreHandle != IntPtr.Zero)
+ CertCloseStore(authSignData.hCertStoreHandle, 0);
+
+ CertCloseStore(hSystemStore, 0);
+ return false;
+ }
+
+ signDataChain.Add(authSignData);
+ GetNestedSignerInfo(ref authSignData, signDataChain);
+
+ for (var i = 0; i < signDataChain.Count; i++)
+ {
+ if (ct.IsCancellationRequested)
+ {
+ CertCloseStore(hSystemStore, 0);
+ return false;
+ }
+
+ var pCurrContext = IntPtr.Zero;
+ var pCounterSigner = IntPtr.Zero;
+ var signNode = new SignNodeInfo();
+
+ GetCounterSignerInfo(signDataChain[i].pSignerInfo, ref pCounterSigner);
+ if (pCounterSigner != IntPtr.Zero)
+ GetCounterSignerData(pCounterSigner, signNode.CounterSign);
+ else
+ GetGeneralizedTimeStamp(signDataChain[i].pSignerInfo, signNode.CounterSign);
+
+ var signerInfo = Marshal.PtrToStructure(signDataChain[i].pSignerInfo);
+ var szObjId = signerInfo.HashAlgorithm.pszObjId;
+ CalculateDigestAlgorithm(szObjId, signNode);
+ (_, signNode.Version) = CalculateSignVersion(signerInfo.dwVersion);
+
+ var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(signerInfo.Issuer, pIssuer, false);
+ pCurrContext = CertFindCertificateInStore(
+ signDataChain[i].hCertStoreHandle,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ CERT_FIND_ISSUER_NAME,
+ pIssuer,
+ IntPtr.Zero
+ );
+ Marshal.FreeHGlobal(pIssuer);
+
+ result = pCurrContext != IntPtr.Zero;
+ while (result)
+ {
+ var pOrigContext = pCurrContext;
+ result = GetSignerSignatureInfo(
+ hSystemStore,
+ signDataChain[i].hCertStoreHandle,
+ pOrigContext,
+ ref pCurrContext,
+ signNode
+ );
+ CertFreeCertificateContext(pOrigContext);
+ }
+
+ if (pCurrContext != IntPtr.Zero)
+ CertFreeCertificateContext(pCurrContext);
+
+ if (pCounterSigner != IntPtr.Zero)
+ Marshal.FreeHGlobal(pCounterSigner);
+
+ if (signDataChain[i].pSignerInfo != IntPtr.Zero)
+ Marshal.FreeHGlobal(signDataChain[i].pSignerInfo);
+
+ if (signDataChain[i].hCertStoreHandle != IntPtr.Zero)
+ CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
+
+ succeded = true;
+ signNode.IsValid = VerifyySignature(fileName);
+ signNode.Index = i;
+ signChain.Add(signNode);
+ }
+
+ CertCloseStore(hSystemStore, 0);
+ return succeded;
+ }
+
+ private static bool VerifyySignature(string certPath)
+ {
+ var actionGuid = new Guid("{00AAC56B-CD44-11D0-8CC2-00C04FC295EE}");
+ var guidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(actionGuid));
+ Marshal.StructureToPtr(actionGuid, guidPtr, false);
+
+ var sFileInfo = Marshal.SizeOf();
+ var fileInfo = new WINTRUST_FILE_INFO
+ {
+ cbStruct = (uint)sFileInfo,
+ pcwszFilePath = Marshal.StringToCoTaskMemAuto(certPath),
+ hFile = IntPtr.Zero,
+ pgKnownSubject = IntPtr.Zero
+ };
+ var filePtr = Marshal.AllocHGlobal(sFileInfo);
+ Marshal.StructureToPtr(fileInfo, filePtr, false);
+
+ var sData = Marshal.SizeOf();
+ var wintrustData = new WINTRUST_DATA
+ {
+ cbStruct = (uint)sData,
+ pPolicyCallbackData = IntPtr.Zero,
+ pSIPClientData = IntPtr.Zero,
+ dwUIChoice = 2, // Display no UI
+ fdwRevocationChecks = 0, // No revocation checking
+ dwUnionChoice = 1, // Verify an embedded signature on a file
+ dwStateAction = 1, // Verify action
+ hVWTStateData = IntPtr.Zero,
+ pwszURLReference = IntPtr.Zero,
+ dwUIContext = 0,
+ pFile = filePtr
+ };
+ var dataPtr = Marshal.AllocHGlobal(sData);
+ Marshal.StructureToPtr(wintrustData, dataPtr, false);
+
+ try
+ {
+ var res = WinVerifyTrust(IntPtr.Zero, guidPtr, dataPtr);
+
+ // Release hWVTStateData
+ wintrustData.dwStateAction = 2; // Close
+ Marshal.StructureToPtr(wintrustData, dataPtr, true);
+ WinVerifyTrust(IntPtr.Zero, guidPtr, dataPtr);
+
+ return res == 0;
+ }
+ finally
+ {
+ if (fileInfo.pcwszFilePath != IntPtr.Zero)
+ Marshal.FreeCoTaskMem(fileInfo.pcwszFilePath);
+
+ Marshal.FreeHGlobal(guidPtr);
+ Marshal.FreeHGlobal(filePtr);
+ Marshal.FreeHGlobal(dataPtr);
+ }
+ }
+
+ private static bool TryGetSignerInfo(
+ string fileName,
+ ref IntPtr hMsg,
+ ref IntPtr hCertStore,
+ ref IntPtr pSignerInfo,
+ ref uint signerSize,
+ uint index = 0)
+ {
+ uint encoding = 0;
+ var pDummy = IntPtr.Zero;
+ uint dummy = 0;
+ var pFileName = Marshal.StringToHGlobalAuto(fileName);
+ var result = CryptQueryObject(
+ CERT_QUERY_OBJECT_FILE,
+ pFileName,
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+ CERT_QUERY_FORMAT_FLAG_BINARY,
+ 0,
+ ref encoding,
+ ref dummy,
+ ref dummy,
+ ref hCertStore,
+ ref hMsg,
+ ref pDummy
+ );
+ Marshal.FreeHGlobal(pFileName);
+
+ if (!result)
+ return false;
+
+ result = CustomCryptMsgGetParam(
+ hMsg,
+ CMSG_SIGNER_INFO_PARAM,
+ index,
+ ref pSignerInfo,
+ ref signerSize
+ );
+
+ return result;
+ }
+
+ private static bool GetCounterSignerInfo(IntPtr pSignerInfo, ref IntPtr pTargetSigner)
+ {
+ uint objSize = 0;
+ if (pSignerInfo == IntPtr.Zero)
+ return false;
+
+ try
+ {
+ var res = TryGetUnauthAttr(pSignerInfo, szOID_RSA_counterSign, out var attr);
+ if (!res)
+ return false;
+
+ var rgValue = Marshal.PtrToStructure(attr.rgValue);
+ var result = CryptDecodeObject(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ PKCS7_SIGNER_INFO,
+ rgValue.pbData,
+ rgValue.cbData,
+ 0,
+ IntPtr.Zero,
+ ref objSize
+ );
+ if (!result)
+ return false;
+
+ pTargetSigner = Marshal.AllocHGlobal((int)objSize * sizeof(byte));
+ if (pTargetSigner == IntPtr.Zero)
+ return false;
+
+ result = CryptDecodeObject(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ PKCS7_SIGNER_INFO,
+ rgValue.pbData,
+ rgValue.cbData,
+ 0,
+ pTargetSigner,
+ ref objSize
+ );
+ if (!result)
+ return false;
+ }
+ finally
+ {
+ }
+
+ return true;
+ }
+
+ private static bool GetCounterSignerData(IntPtr pSignerInfo, SignCounterSign counterSign)
+ {
+ var res = TryGetAuthAttr(pSignerInfo, szOID_RSA_signingTime, out var attr);
+ if (!res)
+ return false;
+
+ var rgValue = Marshal.PtrToStructure(attr.rgValue);
+
+ var data = (uint)Marshal.SizeOf();
+ var ft = Marshal.AllocHGlobal((int)data);
+ IntPtr lft = IntPtr.Zero;
+ IntPtr st = IntPtr.Zero;
+
+ try
+ {
+ var pStructType = Marshal.StringToHGlobalUni(szOID_RSA_signingTime);
+ var result = CryptDecodeObject(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ PKCS_UTC_TIME,
+ rgValue.pbData,
+ rgValue.cbData,
+ 0,
+ ft,
+ ref data
+ );
+ Marshal.FreeHGlobal(pStructType);
+ if (!result)
+ return false;
+
+ lft = Marshal.AllocHGlobal((int)data);
+ st = Marshal.AllocHGlobal(Marshal.SizeOf());
+ FileTimeToLocalFileTime(ft, lft);
+ FileTimeToSystemTime(lft, st);
+ counterSign.TimeStamp = TimeToString(IntPtr.Zero, st);
+
+ return true;
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(ft);
+ if (lft != IntPtr.Zero)
+ Marshal.FreeHGlobal(lft);
+
+ if (st != IntPtr.Zero)
+ Marshal.FreeHGlobal(st);
+ }
+ }
+
+ private static bool ParseDERFindType(
+ int typeSearch,
+ IntPtr pbSignature,
+ uint size,
+ ref uint positionFound,
+ ref uint lengthFound)
+ {
+ uint position = 0;
+ uint sizeFound = 0;
+ uint bytesParsed = 0;
+ var iType = 0;
+ var iClass = 0;
+ positionFound = 0;
+ lengthFound = 0;
+ if (pbSignature == IntPtr.Zero)
+ return false;
+
+ while (size > position)
+ {
+ if (!SafeToReadNBytes(size, position, 2))
+ return false;
+
+ ParseDERType(Marshal.ReadByte(pbSignature, (int)position), ref iType, ref iClass);
+ switch (iType)
+ {
+ case 0x05: // Null
+ ++position;
+ if (Marshal.ReadByte(pbSignature, (int)position) != 0x00)
+ return false;
+
+ ++position;
+ break;
+
+ case 0x06: // Object Identifier
+ ++position;
+ var val = Marshal.ReadByte(pbSignature, (int)position);
+ if (!SafeToReadNBytes(size - position, 1, val))
+ return false;
+
+ position += 1u + val;
+ break;
+
+ case 0x00: // ?
+ case 0x01: // Boolean
+ case 0x02: // Integer
+ case 0x03: // Bit String
+ case 0x04: // Octet String
+ case 0x0A: // enumerated
+ case 0x0C: // UTF8string
+ case 0x13: // printable string
+ case 0x14: // T61 string
+ case 0x16: // IA5String
+ case 0x17: // UTC time
+ case 0x18: // Generalized time
+ case 0x1E: // BMPstring
+ ++position;
+ if (!ParseDERSize(
+ IntPtr.Add(pbSignature, (int)position),
+ size - position,
+ ref sizeFound,
+ ref bytesParsed))
+ {
+ return false;
+ }
+
+ position += bytesParsed;
+ if (!SafeToReadNBytes(size - position, 0, sizeFound))
+ return false;
+
+ if (typeSearch == iType)
+ {
+ positionFound = position;
+ lengthFound = sizeFound;
+
+ return true;
+ }
+
+ position += sizeFound;
+ break;
+
+ case 0x20: // context specific
+ case 0x21: // context specific
+ case 0x23: // context specific
+ case 0x24: // context specific
+ case 0x30: // sequence
+ case 0x31: // set
+ position++;
+ if (!ParseDERSize(
+ IntPtr.Add(pbSignature, (int)position),
+ size - position,
+ ref sizeFound,
+ ref bytesParsed))
+ {
+ return false;
+ }
+
+ position += bytesParsed;
+ break;
+
+ case 0x22: // ?
+ position += 2;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ private static bool GetGeneralizedTimeStamp(
+ IntPtr pSignerInfo,
+ SignCounterSign counter)
+ {
+ uint positionFound = 0;
+ uint lengthFound = 0;
+ var res = TryGetUnauthAttr(pSignerInfo, szOID_RFC3161_counterSign, out var attr);
+ if (!res)
+ return false;
+
+ var rgValue = Marshal.PtrToStructure(attr.rgValue);
+ var result = ParseDERFindType(
+ 0x04,
+ rgValue.pbData,
+ rgValue.cbData,
+ ref positionFound,
+ ref lengthFound);
+ if (!result)
+ return false;
+
+ // Counter Signer Timstamp
+ var pbOctetString = IntPtr.Add(rgValue.pbData, (int)positionFound);
+ counter.TimeStamp = GetTimeStampFromDER(pbOctetString, lengthFound, ref positionFound);
+
+ return true;
+ }
+
+ private static string GetTimeStampFromDER(IntPtr pbOctetString, uint lengthFound, ref uint positionFound)
+ {
+ var result = ParseDERFindType(
+ 0x18,
+ pbOctetString,
+ lengthFound,
+ ref positionFound,
+ ref lengthFound
+ );
+ if (!result)
+ return string.Empty;
+
+ var st = new SYSTEMTIME();
+ var buffer = Marshal.PtrToStringUTF8(
+ IntPtr.Add(pbOctetString, (int)positionFound),
+ (int)lengthFound
+ ) + (char)0;
+
+ _ = short.TryParse(buffer.AsSpan(0, 4), out st.Year);
+ _ = short.TryParse(buffer.AsSpan(4, 2), out st.Month);
+ _ = short.TryParse(buffer.AsSpan(6, 2), out st.Day);
+ _ = short.TryParse(buffer.AsSpan(8, 2), out st.Hour);
+ _ = short.TryParse(buffer.AsSpan(10, 2), out st.Minute);
+ _ = short.TryParse(buffer.AsSpan(12, 2), out st.Second);
+ _ = short.TryParse(buffer.AsSpan(15, 3), out st.Milliseconds);
+
+ var sst = Marshal.AllocHGlobal(Marshal.SizeOf());
+ var lst = Marshal.AllocHGlobal(Marshal.SizeOf());
+ var fft = Marshal.AllocHGlobal(Marshal.SizeOf());
+ var lft = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(st, sst, true);
+ SystemTimeToFileTime(sst, fft);
+ FileTimeToLocalFileTime(fft, lft);
+ FileTimeToSystemTime(lft, lst);
+ var timestamp = TimeToString(IntPtr.Zero, lst);
+
+ Marshal.FreeHGlobal(fft);
+ Marshal.FreeHGlobal(lft);
+ Marshal.FreeHGlobal(sst);
+ Marshal.FreeHGlobal(lst);
+
+ return timestamp;
+ }
+
+ private static bool GetStringFromCertContext(IntPtr pCertContext, uint dwType, uint flag, CertNodeInfoItem info)
+ {
+ var data = CertGetNameStringA(pCertContext, dwType, flag, IntPtr.Zero, IntPtr.Zero, 0);
+ if (data == 0)
+ {
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ var pszTempName = Marshal.AllocHGlobal((int)data * sizeof(byte));
+ if (pszTempName == IntPtr.Zero)
+ {
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ data = CertGetNameStringA(pCertContext, dwType, flag, IntPtr.Zero, pszTempName, data);
+ if (data == 0)
+ {
+ Marshal.FreeHGlobal(pszTempName);
+ return false;
+ }
+
+ if (flag == 0)
+ info.IssuedTo = StripString(Marshal.PtrToStringUTF8(pszTempName));
+ else
+ info.IssuedBy = StripString(Marshal.PtrToStringUTF8(pszTempName));
+
+ Marshal.FreeHGlobal(pszTempName);
+
+ return true;
+ }
+
+ private static bool TryGetUnauthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
+ {
+ int n = 0;
+ var signerInfo = Marshal.PtrToStructure(pSignerInfo);
+ attr = new CRYPT_ATTRIBUTE();
+ for (; n < signerInfo.UnauthAttrs.cbData; n++)
+ {
+ attr = Marshal.PtrToStructure(
+ IntPtr.Add(signerInfo.UnauthAttrs.pbData, n * Marshal.SizeOf())
+ );
+ if (attr.pszObjId == oid)
+ break;
+ }
+
+ return n < signerInfo.UnauthAttrs.cbData;
+ }
+
+ private static bool TryGetAuthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
+ {
+ int n = 0;
+ var signerInfo = Marshal.PtrToStructure(pSignerInfo);
+ attr = new CRYPT_ATTRIBUTE();
+ for (; n < signerInfo.AuthAttrs.cbData; n++)
+ {
+ attr = Marshal.PtrToStructure(
+ IntPtr.Add(signerInfo.AuthAttrs.pbData, n * Marshal.SizeOf())
+ );
+ if (attr.pszObjId == oid)
+ break;
+ }
+
+ return n < signerInfo.AuthAttrs.cbData;
+ }
+
+ private static bool GetNestedSignerInfo(ref SignDataHandle AuthSignData, List NestedChain)
+ {
+ var succeded = false;
+ var hNestedMsg = IntPtr.Zero;
+ if (AuthSignData.pSignerInfo == IntPtr.Zero)
+ return false;
+
+ try
+ {
+ var res = TryGetUnauthAttr(AuthSignData.pSignerInfo, szOID_NESTED_SIGNATURE, out var attr);
+ if (!res)
+ return false;
+
+ var rgValue = Marshal.PtrToStructure(attr.rgValue);
+ var cbCurrData = rgValue.cbData;
+ var pbCurrData = rgValue.pbData;
+
+ var upperBound = IntPtr.Add(AuthSignData.pSignerInfo, (int)AuthSignData.dwObjSize);
+ while (pbCurrData > AuthSignData.pSignerInfo && pbCurrData < upperBound)
+ {
+ var nestedHandle = new SignDataHandle() { dwObjSize = 0 };
+ if (!Memcmp(pbCurrData, SG_ProtoCoded) ||
+ !Memcmp(IntPtr.Add(pbCurrData, 6), SG_SignedData))
+ {
+ break;
+ }
+
+ hNestedMsg = CryptMsgOpenToDecode(
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ 0,
+ 0,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ IntPtr.Zero
+ );
+ if (hNestedMsg == IntPtr.Zero)
+ return false;
+
+ cbCurrData = XCHWordLitend(unchecked((ushort)Marshal.ReadInt16(pbCurrData)) + 2u) + 4u;
+ var pbNextData = pbCurrData;
+ pbNextData = IntPtr.Add(pbNextData, (int)EightByteAlign(cbCurrData, unchecked(pbCurrData)));
+ var result = CryptMsgUpdate(hNestedMsg, pbCurrData, cbCurrData, true);
+ pbCurrData = pbNextData;
+ if (!result)
+ continue;
+
+ result = CustomCryptMsgGetParam(
+ hNestedMsg,
+ CMSG_SIGNER_INFO_PARAM,
+ 0,
+ ref nestedHandle.pSignerInfo,
+ ref nestedHandle.dwObjSize
+ );
+ if (!result)
+ continue;
+
+ nestedHandle.hCertStoreHandle = CertOpenStore(
+ CERT_STORE_PROV_MSG,
+ PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ IntPtr.Zero,
+ 0,
+ hNestedMsg
+ );
+
+ succeded = true;
+ NestedChain.Add(nestedHandle);
+ }
+ }
+ finally
+ {
+ if (hNestedMsg != IntPtr.Zero)
+ CryptMsgClose(hNestedMsg);
+ }
+
+ return succeded;
+ }
+
+ private static bool CustomCryptMsgGetParam(
+ IntPtr hCryptMsg,
+ uint paramType,
+ uint index,
+ ref IntPtr pParam,
+ ref uint outSize)
+ {
+ bool result;
+ uint size = 0;
+
+ result = CryptMsgGetParam(
+ hCryptMsg,
+ paramType,
+ index,
+ IntPtr.Zero,
+ ref size
+ );
+ if (!result)
+ return false;
+
+ pParam = Marshal.AllocHGlobal((int)size);
+ if (pParam == IntPtr.Zero)
+ return false;
+
+ result = CryptMsgGetParam(
+ hCryptMsg,
+ paramType,
+ index,
+ pParam,
+ ref size
+ );
+ if (!result)
+ return false;
+
+ outSize = size;
+ return true;
+ }
+
+ private static ushort XCHWordLitend(uint num)
+ => (ushort)(((((ushort)num) & 0xFF00) >> 8) | (((ushort)num) & 0x00FF) << 8);
+
+ private static long EightByteAlign(long offset, long b)
+ => ((offset + b + 7) & 0xFFFFFFF8L) - (b & 0xFFFFFFF8L);
+
+ private static bool Memcmp(IntPtr ptr1, byte[] arr)
+ {
+ for (var i = 0; i < arr.Length; i++)
+ {
+ if (Marshal.ReadByte(ptr1, i) != arr[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ private static (bool, string) CalculateSignVersion(uint versionNumber)
+ {
+ var res = versionNumber switch
+ {
+ CERT_V1 => "V1",
+ CERT_V2 => "V2",
+ CERT_V3 => "V3",
+ _ => "Unknown",
+ };
+ return (true, res);
+ }
+
+ private static bool CalculateDigestAlgorithm(string pszObjId, SignNodeInfo info)
+ {
+ if (string.IsNullOrWhiteSpace(pszObjId))
+ info.DigestAlgorithm = "Unknown";
+ else if (pszObjId == szOID_OIWSEC_sha1)
+ info.DigestAlgorithm = "SHA1";
+ else if (pszObjId == szOID_RSA_MD5)
+ info.DigestAlgorithm = "MD5";
+ else if (pszObjId == szOID_NIST_sha256)
+ info.DigestAlgorithm = "SHA256";
+ else
+ info.DigestAlgorithm = StripString(pszObjId);
+
+ return true;
+ }
+
+ private static bool SafeToReadNBytes(uint size, uint start, uint requestSize)
+ => size - start >= requestSize;
+
+ private static void ParseDERType(byte bIn, ref int iType, ref int iClass)
+ {
+ iType = bIn & 0x3F;
+ iClass = bIn >> 6;
+ }
+
+ private static uint ReadNumberFromNBytes(IntPtr pbSignature, uint start, uint requestSize)
+ {
+ uint number = 0;
+ for (var i = 0; i < requestSize; i++)
+ number = number * 0x100 + Marshal.ReadByte(pbSignature, (int)(start + i));
+
+ return number;
+ }
+
+ private static bool ParseDERSize(IntPtr pbSignature, uint size, ref uint sizeFound, ref uint bytesParsed)
+ {
+ var val = Marshal.ReadByte(pbSignature);
+ if (val > 0x80 && !SafeToReadNBytes(size, 1, val - 0x80u))
+ return false;
+
+ if (val <= 0x80)
+ {
+ sizeFound = val;
+ bytesParsed = 1;
+ }
+ else
+ {
+ sizeFound = ReadNumberFromNBytes(pbSignature, 1, val - 0x80u);
+ bytesParsed = val - 0x80u + 1;
+ }
+
+ return true;
+ }
+
+ private static string StripString(string? str)
+ {
+ return str?
+ .Replace("\t", "")?
+ .Replace("\n", "")?
+ .Replace("\r", "")?
+ .Replace(((char)0).ToString(), "") ?? string.Empty;
+ }
+
+ private static string TimeToString(IntPtr pftIn, IntPtr pstIn = 0)
+ {
+ if (pstIn == IntPtr.Zero)
+ {
+ if (pftIn == IntPtr.Zero)
+ return string.Empty;
+
+ pstIn = Marshal.AllocHGlobal(Marshal.SizeOf());
+ FileTimeToSystemTime(pftIn, pstIn);
+ }
+
+ var st = Marshal.PtrToStructure(pstIn);
+ var date = new DateTime(
+ st.Year, st.Month, st.Day,
+ st.Hour, st.Minute, st.Second
+ );
+
+ return formatter.ToLongLabel(date);
+ }
+
+ class SignCounterSign
+ {
+ public string TimeStamp { get; set; } = string.Empty;
+ }
+
+ class SignNodeInfo
+ {
+ public bool IsValid { get; set; } = false;
+ public string DigestAlgorithm { get; set; } = string.Empty;
+ public string Version { get; set; } = string.Empty;
+ public int Index { get; set; } = 0;
+ public SignCounterSign CounterSign { get; set; } = new();
+ public List CertChain = [];
+ }
+ }
}
diff --git a/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs b/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
index b3029eb9c41e..64d64f8806a1 100644
--- a/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
@@ -33,16 +33,16 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
var page = value.ItemType switch
{
- PropertiesNavigationViewItemType.General => typeof(GeneralPage),
- PropertiesNavigationViewItemType.Shortcut => typeof(ShortcutPage),
- PropertiesNavigationViewItemType.Library => typeof(LibraryPage),
- PropertiesNavigationViewItemType.Details => typeof(DetailsPage),
- PropertiesNavigationViewItemType.Security => typeof(SecurityPage),
+ PropertiesNavigationViewItemType.General => typeof(GeneralPage),
+ PropertiesNavigationViewItemType.Shortcut => typeof(ShortcutPage),
+ PropertiesNavigationViewItemType.Library => typeof(LibraryPage),
+ PropertiesNavigationViewItemType.Details => typeof(DetailsPage),
+ PropertiesNavigationViewItemType.Security => typeof(SecurityPage),
PropertiesNavigationViewItemType.Customization => typeof(CustomizationPage),
PropertiesNavigationViewItemType.Compatibility => typeof(CompatibilityPage),
- PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
- PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
- _ => typeof(GeneralPage),
+ PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
+ PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
+ _ => typeof(GeneralPage),
};
_mainFrame?.Navigate(page, parameter, new EntranceNavigationTransitionInfo());
diff --git a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
index e93a411f0803..9273142c7fea 100644
--- a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
@@ -6,28 +6,28 @@
namespace Files.App.ViewModels.Properties
{
- public sealed partial class SignaturesViewModel : ObservableObject, IDisposable
- {
- private CancellationTokenSource _cancellationTokenSource;
+ public sealed partial class SignaturesViewModel : ObservableObject, IDisposable
+ {
+ private CancellationTokenSource _cancellationTokenSource;
- public ObservableCollection Signatures { get; set; }
+ public ObservableCollection Signatures { get; set; }
- public SignaturesViewModel(ListedItem item, AppWindow appWindow)
- {
- _cancellationTokenSource = new();
- Signatures = new();
- var hWnd = Microsoft.UI.Win32Interop.GetWindowFromWindowId(appWindow.Id);
- DigitalSignaturesUtil.LoadItemSignatures(
- item.ItemPath,
- Signatures,
- hWnd,
- _cancellationTokenSource.Token
- );
- }
+ public SignaturesViewModel(ListedItem item, AppWindow appWindow)
+ {
+ _cancellationTokenSource = new();
+ Signatures = new();
+ var hWnd = Microsoft.UI.Win32Interop.GetWindowFromWindowId(appWindow.Id);
+ DigitalSignaturesUtil.LoadItemSignatures(
+ item.ItemPath,
+ Signatures,
+ hWnd,
+ _cancellationTokenSource.Token
+ );
+ }
- public void Dispose()
- {
- _cancellationTokenSource.Cancel();
- }
- }
+ public void Dispose()
+ {
+ _cancellationTokenSource.Cancel();
+ }
+ }
}
diff --git a/src/Files.App/Views/Properties/SignaturesPage.xaml b/src/Files.App/Views/Properties/SignaturesPage.xaml
index 9f507ea38c9b..69cd44ae3815 100644
--- a/src/Files.App/Views/Properties/SignaturesPage.xaml
+++ b/src/Files.App/Views/Properties/SignaturesPage.xaml
@@ -27,7 +27,7 @@
-
+
diff --git a/src/Files.App/Views/Properties/SignaturesPage.xaml.cs b/src/Files.App/Views/Properties/SignaturesPage.xaml.cs
index 01ad04bdd6a4..74e30800dcd2 100644
--- a/src/Files.App/Views/Properties/SignaturesPage.xaml.cs
+++ b/src/Files.App/Views/Properties/SignaturesPage.xaml.cs
@@ -6,35 +6,35 @@
namespace Files.App.Views.Properties
{
- public sealed partial class SignaturesPage : BasePropertiesPage
- {
- private SignaturesViewModel SignaturesViewModel { get; set; }
-
- public SignaturesPage()
- {
- InitializeComponent();
- }
-
- protected override void OnNavigatedTo(NavigationEventArgs e)
- {
- var np = (PropertiesPageNavigationParameter)e.Parameter;
- if (np.Parameter is ListedItem listedItem)
- SignaturesViewModel = new(listedItem, np.Window.AppWindow);
-
- base.OnNavigatedTo(e);
- }
-
- protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
- => Dispose();
-
- public override Task SaveChangesAsync()
- {
- return Task.FromResult(true);
- }
-
- public override void Dispose()
- {
- SignaturesViewModel.Dispose();
- }
- }
+ public sealed partial class SignaturesPage : BasePropertiesPage
+ {
+ private SignaturesViewModel SignaturesViewModel { get; set; }
+
+ public SignaturesPage()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ var np = (PropertiesPageNavigationParameter)e.Parameter;
+ if (np.Parameter is ListedItem listedItem)
+ SignaturesViewModel = new(listedItem, np.Window.AppWindow);
+
+ base.OnNavigatedTo(e);
+ }
+
+ protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
+ => Dispose();
+
+ public override Task SaveChangesAsync()
+ {
+ return Task.FromResult(true);
+ }
+
+ public override void Dispose()
+ {
+ SignaturesViewModel.Dispose();
+ }
+ }
}
From 9b746145cc4cc4686680b8d4ab255528cc4bb7c9 Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Sun, 27 Jul 2025 22:49:32 +0200
Subject: [PATCH 05/10] Again spacing
---
.../Properties/MainPropertiesViewModel.cs | 14 +-
.../Views/Properties/SignaturesPage.xaml | 352 +++++++++---------
2 files changed, 183 insertions(+), 183 deletions(-)
diff --git a/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs b/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
index 64d64f8806a1..58088f9403c7 100644
--- a/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
@@ -33,15 +33,15 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
var page = value.ItemType switch
{
- PropertiesNavigationViewItemType.General => typeof(GeneralPage),
- PropertiesNavigationViewItemType.Shortcut => typeof(ShortcutPage),
- PropertiesNavigationViewItemType.Library => typeof(LibraryPage),
- PropertiesNavigationViewItemType.Details => typeof(DetailsPage),
- PropertiesNavigationViewItemType.Security => typeof(SecurityPage),
+ PropertiesNavigationViewItemType.General => typeof(GeneralPage),
+ PropertiesNavigationViewItemType.Shortcut => typeof(ShortcutPage),
+ PropertiesNavigationViewItemType.Library => typeof(LibraryPage),
+ PropertiesNavigationViewItemType.Details => typeof(DetailsPage),
+ PropertiesNavigationViewItemType.Security => typeof(SecurityPage),
PropertiesNavigationViewItemType.Customization => typeof(CustomizationPage),
PropertiesNavigationViewItemType.Compatibility => typeof(CompatibilityPage),
- PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
- PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
+ PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
+ PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
_ => typeof(GeneralPage),
};
diff --git a/src/Files.App/Views/Properties/SignaturesPage.xaml b/src/Files.App/Views/Properties/SignaturesPage.xaml
index 69cd44ae3815..f6f6b2bb6d31 100644
--- a/src/Files.App/Views/Properties/SignaturesPage.xaml
+++ b/src/Files.App/Views/Properties/SignaturesPage.xaml
@@ -13,184 +13,184 @@
Tag="Signatures"
mc:Ignorable="d">
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From ef28600012dab75b94f2a52f2361fe267226d45b Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Sun, 27 Jul 2025 22:51:00 +0200
Subject: [PATCH 06/10] ... spacing
---
.../Properties/MainPropertiesViewModel.cs | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs b/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
index 58088f9403c7..32c1c4529a01 100644
--- a/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
@@ -33,15 +33,15 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
var page = value.ItemType switch
{
- PropertiesNavigationViewItemType.General => typeof(GeneralPage),
- PropertiesNavigationViewItemType.Shortcut => typeof(ShortcutPage),
- PropertiesNavigationViewItemType.Library => typeof(LibraryPage),
- PropertiesNavigationViewItemType.Details => typeof(DetailsPage),
- PropertiesNavigationViewItemType.Security => typeof(SecurityPage),
+ PropertiesNavigationViewItemType.General => typeof(GeneralPage),
+ PropertiesNavigationViewItemType.Shortcut => typeof(ShortcutPage),
+ PropertiesNavigationViewItemType.Library => typeof(LibraryPage),
+ PropertiesNavigationViewItemType.Details => typeof(DetailsPage),
+ PropertiesNavigationViewItemType.Security => typeof(SecurityPage),
PropertiesNavigationViewItemType.Customization => typeof(CustomizationPage),
PropertiesNavigationViewItemType.Compatibility => typeof(CompatibilityPage),
- PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
- PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
+ PropertiesNavigationViewItemType.Hashes => typeof(HashesPage),
+ PropertiesNavigationViewItemType.Signatures => typeof(SignaturesPage),
_ => typeof(GeneralPage),
};
From 571d0a2f12ae9a3fabfb3f5ec4065776794ff33b Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Mon, 28 Jul 2025 09:55:17 +0200
Subject: [PATCH 07/10] Requested changes
---
.../Enums/PropertiesNavigationViewItemType.cs | 10 +++++-----
.../PropertiesNavigationViewItemFactory.cs | 18 ++++++++++++++++--
src/Files.App/Strings/en-US/Resources.resw | 3 +++
.../Properties/SignaturesViewModel.cs | 3 +++
.../Views/Properties/SignaturesPage.xaml | 18 ++++++++++++++++--
5 files changed, 43 insertions(+), 9 deletions(-)
diff --git a/src/Files.App/Data/Enums/PropertiesNavigationViewItemType.cs b/src/Files.App/Data/Enums/PropertiesNavigationViewItemType.cs
index 766bb13cc863..811d70c3474e 100644
--- a/src/Files.App/Data/Enums/PropertiesNavigationViewItemType.cs
+++ b/src/Files.App/Data/Enums/PropertiesNavigationViewItemType.cs
@@ -48,9 +48,9 @@ public enum PropertiesNavigationViewItemType
///
Shortcut,
- ///
- /// Signatures page type
- ///
- Signatures,
- }
+ ///
+ /// Signatures page type
+ ///
+ Signatures,
+ }
}
diff --git a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
index 7e4efccd40b6..68ee970dcd5c 100644
--- a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
+++ b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
@@ -3,12 +3,25 @@
using Files.Shared.Helpers;
using Microsoft.UI.Xaml;
+using System.Collections.Frozen;
using Windows.Storage;
namespace Files.App.Data.Factories
{
public static class PropertiesNavigationViewItemFactory
{
+ private static readonly FrozenSet _signableTypes = new HashSet()
+ {
+ ".aab", ".apk", ".application", ".appx", ".appxbundle", ".arx", ".cab", ".cat", ".cbx",
+ ".cpl", ".crx", ".dbx", ".deploy", ".dll", ".doc", ".docm", ".dot", ".dotm", ".drx",
+ ".ear", ".efi", ".exe", ".jar", ".js", ".manifest", ".mpp", ".mpt", ".msi", ".msix",
+ ".msixbundle", ".msm", ".msp", ".nupkg", ".ocx", ".pot", ".potm", ".ppa", ".ppam", ".pps",
+ ".ppsm", ".ppt", ".pptm", ".ps1", ".psm1", ".psi", ".pub", ".sar", ".stl", ".sys", ".vbs",
+ ".vdw", ".vdx", ".vsd", ".vsdm", ".vss", ".vssm", ".vst", ".vstm", ".vsto", ".vsix", ".vsx", ".vtx",
+ ".vxd", ".war", ".wiz", ".wsf", ".xap", ".xla", ".xlam", ".xls", ".xlsb", ".xlsm", ".xlt",
+ ".xltm", ".xlsm", ".xsn"
+ }.ToFrozenSet();
+
public static ObservableCollection Initialize(object item)
{
ObservableCollection PropertiesNavigationViewItems = [];
@@ -110,15 +123,16 @@ public static ObservableCollection Initialize
var detailsItemEnabled = !(isFolder && !listedItem.IsArchive) && !isLibrary && !listedItem.IsRecycleBinItem;
var customizationItemEnabled = !isLibrary && (isFolder && !listedItem.IsArchive || isShortcut && !listedItem.IsLinkItem);
var compatibilityItemEnabled = FileExtensionHelpers.IsExecutableFile(listedItem is IShortcutItem sht ? sht.TargetPath : fileExt, true);
+ var signaturesItemEnabled = !isFolder && !isLibrary && !listedItem.IsRecycleBinItem && _signableTypes.Contains(fileExt);
if (!securityItemEnabled)
PropertiesNavigationViewItems.Remove(securityItem);
if (!hashItemEnabled)
- {
PropertiesNavigationViewItems.Remove(hashesItem);
+
+ if (!signaturesItemEnabled)
PropertiesNavigationViewItems.Remove(signaturesItem);
- }
if (!isShortcut)
PropertiesNavigationViewItems.Remove(shortcutItem);
diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw
index ee4b96cca8ba..202beff93061 100644
--- a/src/Files.App/Strings/en-US/Resources.resw
+++ b/src/Files.App/Strings/en-US/Resources.resw
@@ -4291,4 +4291,7 @@
Valid to:
+
+ No signature was found.
+
diff --git a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
index 9273142c7fea..92e696953c4f 100644
--- a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
@@ -12,11 +12,14 @@ public sealed partial class SignaturesViewModel : ObservableObject, IDisposable
public ObservableCollection Signatures { get; set; }
+ public bool NoSignatureFound => Signatures.Count == 0;
+
public SignaturesViewModel(ListedItem item, AppWindow appWindow)
{
_cancellationTokenSource = new();
Signatures = new();
var hWnd = Microsoft.UI.Win32Interop.GetWindowFromWindowId(appWindow.Id);
+ Signatures.CollectionChanged += (s, e) => OnPropertyChanged(nameof(NoSignatureFound));
DigitalSignaturesUtil.LoadItemSignatures(
item.ItemPath,
Signatures,
diff --git a/src/Files.App/Views/Properties/SignaturesPage.xaml b/src/Files.App/Views/Properties/SignaturesPage.xaml
index f6f6b2bb6d31..37c51a6ac4ea 100644
--- a/src/Files.App/Views/Properties/SignaturesPage.xaml
+++ b/src/Files.App/Views/Properties/SignaturesPage.xaml
@@ -23,16 +23,30 @@
x:Key="BoolToBrushConverter"
FalseValue="{ThemeResource SystemFillColorCriticalBrush}"
TrueValue="{ThemeResource SystemFillColorSuccessBrush}" />
+
+
+
-
-
+
From fa0651129b2742cb17833cb3d0fe3b62b14f0549 Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Wed, 30 Jul 2025 10:02:09 +0200
Subject: [PATCH 08/10] Use CsWin32
---
src/Files.App.CsWin32/NativeMethods.txt | 32 +
.../Data/Models/SignatureInfoItem.cs | 5 +-
.../Helpers/Win32/Win32PInvoke.Methods.cs | 132 +---
.../Helpers/Win32/Win32PInvoke.Structs.cs | 154 +---
.../Utils/Signatures/DigitalSignaturesUtil.cs | 731 ++++++++----------
.../Properties/SignaturesViewModel.cs | 3 +-
6 files changed, 399 insertions(+), 658 deletions(-)
diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt
index 294dcf68ab36..cec0a27850aa 100644
--- a/src/Files.App.CsWin32/NativeMethods.txt
+++ b/src/Files.App.CsWin32/NativeMethods.txt
@@ -236,3 +236,35 @@ GetMenuItemCount
GetMenuItemInfo
IsWow64Process2
GetCurrentProcess
+CertFreeCertificateContext
+CryptMsgGetParam
+CryptMsgClose
+CryptMsgOpenToDecode
+CryptMsgUpdate
+CertOpenStore
+CryptDecodeObject
+CertFindCertificateInStore
+CertComparePublicKeyInfo
+CryptQueryObject
+CertCloseStore
+WinVerifyTrust
+FileTimeToSystemTime
+FileTimeToLocalFileTime
+SystemTimeToFileTime
+CRYPTOAPI_BLOB
+CMSG_SIGNER_INFO
+SignDataHandle
+CRYPT_ATTRIBUTE
+FILETIME
+CRYPT_BIT_BLOB
+CERT_ALT_NAME_INFO
+CERT_CONTEXT
+CERT_INFO
+CRYPT_ALGORITHM_IDENTIFIER
+CERT_PUBLIC_KEY_INFO
+CATALOG_INFO
+WINTRUST_FILE_INFO
+WINTRUST_DATA
+HCERTSTORE
+HCRYPTMSG
+CERT_QUERY_ENCODING_TYPE
diff --git a/src/Files.App/Data/Models/SignatureInfoItem.cs b/src/Files.App/Data/Models/SignatureInfoItem.cs
index d58fb5b4eab4..6b5e8ffc5022 100644
--- a/src/Files.App/Data/Models/SignatureInfoItem.cs
+++ b/src/Files.App/Data/Models/SignatureInfoItem.cs
@@ -3,6 +3,7 @@
using Files.App.Utils.Signatures;
using System.Windows.Input;
+using Windows.Win32.Foundation;
namespace Files.App.Data.Models
{
@@ -10,7 +11,7 @@ public sealed partial class SignatureInfoItem : ObservableObject
{
private readonly string _fileName;
- private readonly IntPtr _hwndParent;
+ private readonly HWND _hwndParent;
private readonly int _index;
@@ -73,7 +74,7 @@ public bool Verified
public ICommand OpenDetailsCommand { get; }
- public SignatureInfoItem(string fileName, int index, IntPtr hWnd, List chain)
+ public SignatureInfoItem(string fileName, int index, HWND hWnd, List chain)
{
_fileName = fileName;
_hwndParent = hWnd;
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
index 7ff329b089b1..1b9eeecd7c47 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
@@ -5,6 +5,7 @@
using System.Runtime.InteropServices;
using System.Text;
using Windows.Win32.Foundation;
+using Windows.Win32.Security.Cryptography;
using Windows.Win32.System.Com;
namespace Files.App.Helpers
@@ -349,138 +350,17 @@ out IntPtr pszPath
// crypt32.dll
[DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern uint CertGetNameStringA(
- IntPtr pCertContext,
+ public unsafe static extern uint CertGetNameStringA(
+ CERT_CONTEXT* pCertContext,
uint dwType,
uint dwFlags,
- IntPtr pvTypePara,
- IntPtr pszNameString,
+ void* pvTypePara,
+ PCSTR pszNameString,
uint cchNameString
);
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CertFreeCertificateContext(
- IntPtr pCertContext
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptMsgGetParam(
- IntPtr hCryptMsg,
- uint dwParamType,
- uint dwIndex,
- IntPtr pParam,
- ref uint dwOutSize
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptMsgClose(
- IntPtr hCryptMsg
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern IntPtr CryptMsgOpenToDecode(
- uint dwMsgEncodingType,
- uint dwFlags,
- uint dwMsgType,
- IntPtr hCryptProv,
- IntPtr pRecipientInfo,
- IntPtr pStreamInfo
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptMsgUpdate(
- IntPtr hCryptMsg,
- IntPtr pbData,
- uint cbDatam,
- bool fFinal
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern IntPtr CertOpenStore(
- IntPtr lpszStoreProvider,
- uint dwEncodingType,
- IntPtr hCryptProv,
- uint dwFlags,
- IntPtr pvPara
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptDecodeObject(
- uint dwCertEncodingType,
- IntPtr lpszStructType,
- IntPtr pbEncoded,
- uint cbEncoded,
- uint dwFlags,
- IntPtr pvStructInfo,
- ref uint pcbStructInfo
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern IntPtr CertFindCertificateInStore(
- IntPtr hCertStore,
- uint dwCertEncodingType,
- uint dwFindFlags,
- uint dwFindType,
- IntPtr pvFindPara,
- IntPtr pPrevCertContext
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CertComparePublicKeyInfo(
- uint dwCertEncodingType,
- IntPtr pPublicKey1,
- IntPtr pPublicKey2
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CryptQueryObject(
- uint dwObjectType,
- IntPtr pvObject,
- uint dwExpectedContentTypeFlags,
- uint dwExpectedFormatTypeFlags,
- uint dwFlags,
- ref uint pdwMsgAndCertEncodingType,
- ref uint pdwContentType,
- ref uint pdwFormatType,
- ref IntPtr phCertStore,
- ref IntPtr phMsg,
- ref IntPtr ppvContext
- );
-
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool CertCloseStore(
- IntPtr hCertStore,
- uint dwFlags
- );
-
- [DllImport("wintrust.dll")]
- public static extern long WinVerifyTrust(
- IntPtr hwnd,
- IntPtr pgActionID,
- IntPtr pWVTData
- );
-
- // kernel32.dll
- [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool FileTimeToSystemTime(
- IntPtr lpFileTime,
- IntPtr lpSystemTime
- );
-
- [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool FileTimeToLocalFileTime(
- IntPtr lpFileTime,
- IntPtr lpLocalFileTime
- );
-
- [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public static extern bool SystemTimeToFileTime(
- IntPtr lpSystemTime,
- IntPtr lpFileTime
- );
-
// cryptui.dll
[DllImport("cryptui.dll", SetLastError = true, CharSet = CharSet.Auto)]
- public static extern bool CryptUIDlgViewSignerInfo(IntPtr pViewInfo);
+ public unsafe static extern bool CryptUIDlgViewSignerInfo(CRYPTUI_VIEWSIGNERINFO_STRUCT* pViewInfo);
}
}
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
index 0ba1c5f1bca3..d1453d5cd285 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Structs.cs
@@ -3,6 +3,8 @@
using System.IO;
using System.Runtime.InteropServices;
+using Windows.Win32.Foundation;
+using Windows.Win32.Security.Cryptography;
namespace Files.App.Helpers
{
@@ -199,159 +201,35 @@ public struct WIN32_FIND_DATA
}
[StructLayout(LayoutKind.Sequential)]
- public struct CRYPTOAPI_BLOB
- {
- public uint cbData;
- public IntPtr pbData;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CMSG_SIGNER_INFO
- {
- public uint dwVersion;
- public CRYPTOAPI_BLOB Issuer;
- public CRYPTOAPI_BLOB SerialNumber;
- public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
- public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
- public CRYPTOAPI_BLOB EncryptedHash;
- public CRYPTOAPI_BLOB AuthAttrs;
- public CRYPTOAPI_BLOB UnauthAttrs;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct SignDataHandle
+ public unsafe struct SignDataHandle
{
public uint dwObjSize;
- public IntPtr pSignerInfo;
- public IntPtr hCertStoreHandle;
+ public CMSG_SIGNER_INFO* pSignerInfo;
+ public HCERTSTORE hCertStoreHandle;
}
[StructLayout(LayoutKind.Sequential)]
- public struct CRYPT_ATTRIBUTE
+ public unsafe struct CRYPTOAPI_BLOB
{
- [MarshalAs(UnmanagedType.LPStr)]
- public string pszObjId;
- public uint cValue;
- public IntPtr rgValue;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct FILETIME
- {
- public uint dwLowDateTime;
- public uint dwHighDateTime;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CRYPT_BIT_BLOB
- {
- private readonly uint cbData;
- private readonly IntPtr pbData;
- private readonly uint cUnusedBits;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CERT_ALT_NAME_INFO
- {
- public uint cAltEntry;
- public IntPtr rgAltEntry;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CERT_CONTEXT
- {
- public uint dwCertEncodingType;
- public IntPtr pbCertEncoded;
- public uint cbCertEncoded;
- public IntPtr pCertInfo;
- public IntPtr hCertStore;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CERT_INFO
- {
- public uint dwVersion;
- public CRYPTOAPI_BLOB SerialNumber;
- public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
- public CRYPTOAPI_BLOB Issuer;
- public FILETIME NotBefore;
- public FILETIME NotAfter;
- public CRYPTOAPI_BLOB Subject;
- public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
- public CRYPT_BIT_BLOB IssuerUniqueId;
- public CRYPT_BIT_BLOB SubjectUniqueId;
- public uint cExtension;
- public IntPtr rgExtension;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CRYPT_ALGORITHM_IDENTIFIER
- {
- [MarshalAs(UnmanagedType.LPStr)]
- public string pszObjId;
- public CRYPTOAPI_BLOB Parameters;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CERT_PUBLIC_KEY_INFO
- {
- public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
- public CRYPTOAPI_BLOB PublicKey;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct CATALOG_INFO
- {
- public uint cbStruct;
- public char[] wszCatalogFile = new char[256];
-
- public CATALOG_INFO()
- {
- }
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct WINTRUST_FILE_INFO
- {
- public uint cbStruct;
- public IntPtr pcwszFilePath;
- public IntPtr hFile;
- public IntPtr pgKnownSubject;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct WINTRUST_DATA
- {
- public uint cbStruct;
- public IntPtr pPolicyCallbackData;
- public IntPtr pSIPClientData;
- public uint dwUIChoice;
- public uint fdwRevocationChecks;
- public uint dwUnionChoice;
- public IntPtr pFile;
- public uint dwStateAction;
- public IntPtr hVWTStateData;
- public IntPtr pwszURLReference;
- public uint dwProvFlags;
- public uint dwUIContext;
- public IntPtr pSignatureSettings;
+ public uint cbData;
+ public void* pbData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
- public struct CRYPTUI_VIEWSIGNERINFO_STRUCT
+ public unsafe struct CRYPTUI_VIEWSIGNERINFO_STRUCT
{
public uint dwSize;
- public IntPtr hwndParent;
+ public HWND hwndParent;
public uint dwFlags;
- public IntPtr szTitle;
- public IntPtr pSignerInfo;
- public IntPtr hMsg;
- public IntPtr pszOID;
+ public PCSTR szTitle;
+ public CMSG_SIGNER_INFO* pSignerInfo;
+ public void* hMsg;
+ public PCSTR pszOID;
public uint? dwReserved;
public uint cStores;
- public IntPtr rghStores;
+ public HCERTSTORE* rghStores;
public uint cPropPages;
- public IntPtr rgPropPages;
+ public void* rgPropPages;
}
}
}
diff --git a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
index 69ef278dbcb4..0d4386b5412b 100644
--- a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
+++ b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
@@ -2,6 +2,10 @@
// Licensed under the MIT License.
using System.Runtime.InteropServices;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.Security.Cryptography;
+using Windows.Win32.Security.WinTrust;
using static Files.App.Helpers.Win32PInvoke;
namespace Files.App.Utils.Signatures
@@ -19,20 +23,11 @@ public static class DigitalSignaturesUtil
// Flags
private const uint CERT_NAME_SIMPLE_DISPLAY_TYPE = 4;
- private const uint CERT_FIND_SUBJECT_NAME = 131079;
- private const uint CERT_FIND_ISSUER_NAME = 131076;
- private const uint CERT_QUERY_OBJECT_FILE = 0x00000001;
- private const uint CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = 0x00000400;
- private const uint CERT_QUERY_FORMAT_FLAG_BINARY = 0x00000002;
private const uint CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000;
- private const IntPtr CERT_STORE_PROV_SYSTEM = 10;
- private const IntPtr CERT_STORE_PROV_MSG = 1;
-
private const uint PKCS_7_ASN_ENCODING = 0x00010000;
private const uint CRYPT_ASN_ENCODING = 0x00000001;
-
- private const IntPtr PKCS7_SIGNER_INFO = 500;
- private const IntPtr PKCS_UTC_TIME = 17;
+ private const CERT_QUERY_ENCODING_TYPE ENCODING =
+ CERT_QUERY_ENCODING_TYPE.X509_ASN_ENCODING | CERT_QUERY_ENCODING_TYPE.PKCS_7_ASN_ENCODING;
private const uint CMSG_SIGNER_INFO_PARAM = 6;
@@ -54,7 +49,7 @@ public static class DigitalSignaturesUtil
public static void LoadItemSignatures(
string filePath,
ObservableCollection signatures,
- IntPtr hWnd,
+ HWND hWnd,
CancellationToken ct)
{
var signChain = new List();
@@ -79,12 +74,12 @@ public static void LoadItemSignatures(
}
}
- public static void DisplaySignerInfoDialog(string filePath, IntPtr hwndParent, int index)
+ public unsafe static void DisplaySignerInfoDialog(string filePath, HWND hwndParent, int index)
{
if (string.IsNullOrEmpty(filePath))
return;
- var hAuthCryptMsg = IntPtr.Zero;
+ void* hAuthCryptMsg = null;
var signHandle = new SignDataHandle();
var signDataChain = new List();
@@ -92,12 +87,12 @@ public static void DisplaySignerInfoDialog(string filePath, IntPtr hwndParent, i
{
var result = TryGetSignerInfo(
filePath,
- ref hAuthCryptMsg,
- ref signHandle.hCertStoreHandle,
- ref signHandle.pSignerInfo,
- ref signHandle.dwObjSize
+ out hAuthCryptMsg,
+ out signHandle.hCertStoreHandle,
+ out signHandle.pSignerInfo,
+ out signHandle.dwObjSize
);
- if (!result || signHandle.pSignerInfo == IntPtr.Zero)
+ if (!result || signHandle.pSignerInfo is null)
return;
signDataChain.Add(signHandle);
@@ -106,19 +101,16 @@ ref signHandle.dwObjSize
return;
signHandle = signDataChain[index];
- var signerInfo = Marshal.PtrToStructure(signHandle.pSignerInfo);
- var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(signerInfo.Issuer, pIssuer, false);
- var pCertContext = CertFindCertificateInStore(
+ var issuer = signHandle.pSignerInfo->Issuer;
+ var pCertContext = PInvoke.CertFindCertificateInStore(
signHandle.hCertStoreHandle,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ ENCODING,
0,
- CERT_FIND_ISSUER_NAME,
- pIssuer,
- IntPtr.Zero
+ CERT_FIND_FLAGS.CERT_FIND_ISSUER_NAME,
+ &issuer,
+ null
);
- Marshal.FreeHGlobal(pIssuer);
- if (pCertContext == IntPtr.Zero)
+ if (pCertContext is null)
return;
var viewInfo = new CRYPTUI_VIEWSIGNERINFO_STRUCT
@@ -126,25 +118,21 @@ ref signHandle.dwObjSize
dwSize = (uint)Marshal.SizeOf(),
hwndParent = hwndParent,
dwFlags = 0,
- szTitle = IntPtr.Zero,
+ szTitle = (PCSTR)null,
pSignerInfo = signHandle.pSignerInfo,
hMsg = hAuthCryptMsg,
- pszOID = IntPtr.Zero,
+ pszOID = (PCSTR)null,
dwReserved = null,
cStores = 1,
- rghStores = Marshal.AllocHGlobal(IntPtr.Size),
+ rghStores = (HCERTSTORE*)NativeMemory.Alloc((uint)sizeof(void*)),
cPropPages = 0,
- rgPropPages = IntPtr.Zero
+ rgPropPages = null
};
- Marshal.WriteIntPtr(viewInfo.rghStores, signHandle.hCertStoreHandle);
- var pViewInfo = Marshal.AllocHGlobal((int)viewInfo.dwSize);
- Marshal.StructureToPtr(viewInfo, pViewInfo, false);
+ *(viewInfo.rghStores) = signHandle.hCertStoreHandle;
- result = CryptUIDlgViewSignerInfo(pViewInfo);
+ result = CryptUIDlgViewSignerInfo(&viewInfo);
- Marshal.FreeHGlobal(viewInfo.rghStores);
- Marshal.FreeHGlobal(pViewInfo);
- CertFreeCertificateContext(pCertContext);
+ PInvoke.CertFreeCertificateContext(pCertContext);
}
finally
{
@@ -152,130 +140,113 @@ ref signHandle.dwObjSize
// you must release them starting from the last one.
for (int i = signDataChain.Count - 1; i >= 0; i--)
{
- if (signDataChain[i].pSignerInfo != IntPtr.Zero)
- Marshal.FreeHGlobal(signDataChain[i].pSignerInfo);
+ if (signDataChain[i].pSignerInfo is not null)
+ NativeMemory.Free(signDataChain[i].pSignerInfo);
- if (signDataChain[i].hCertStoreHandle != IntPtr.Zero)
- CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
+ if (!signDataChain[i].hCertStoreHandle.IsNull)
+ PInvoke.CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
}
- if (hAuthCryptMsg != IntPtr.Zero)
- CryptMsgClose(hAuthCryptMsg);
+ if (hAuthCryptMsg is not null)
+ PInvoke.CryptMsgClose(hAuthCryptMsg);
}
}
- private static bool GetSignerSignatureInfo(
- IntPtr hSystemStore,
- IntPtr hCertStore,
- IntPtr pOrigContext,
- ref IntPtr pCurrContext,
+ private unsafe static bool GetSignerSignatureInfo(
+ HCERTSTORE hSystemStore,
+ HCERTSTORE hCertStore,
+ CERT_CONTEXT* pOrigContext,
+ ref CERT_CONTEXT* pCurrContext,
SignNodeInfo signNode)
{
- var currContext = Marshal.PtrToStructure(pCurrContext);
- var pCertInfo = currContext.pCertInfo;
+ var pCertInfo = pCurrContext->pCertInfo;
var certNode = new CertNodeInfoItem();
- var certInfo = Marshal.PtrToStructure(pCertInfo);
- (_, certNode.Version) = CalculateSignVersion(certInfo.dwVersion);
+ (_, certNode.Version) = CalculateSignVersion(pCertInfo->dwVersion);
GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, certNode);
GetStringFromCertContext(pCurrContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 1, certNode);
- var pft = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(certInfo.NotBefore, pft, false);
+ var pft = &(pCertInfo->NotBefore);
certNode.ValidFrom = TimeToString(pft);
- Marshal.StructureToPtr(certInfo.NotAfter, pft, false);
+ pft = &(pCertInfo->NotAfter);
certNode.ValidTo = TimeToString(pft);
- Marshal.FreeHGlobal(pft);
signNode.CertChain.Add(certNode);
- var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(certInfo.Issuer, pIssuer, false);
- pCurrContext = CertFindCertificateInStore(
+ pCurrContext = PInvoke.CertFindCertificateInStore(
hCertStore,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ ENCODING,
0,
- CERT_FIND_SUBJECT_NAME,
- pIssuer,
- IntPtr.Zero
+ CERT_FIND_FLAGS.CERT_FIND_SUBJECT_NAME,
+ &(pCertInfo->Issuer),
+ null
);
- if (pCurrContext == IntPtr.Zero)
+ if (pCurrContext is null)
{
- pCurrContext = CertFindCertificateInStore(
+ pCurrContext = PInvoke.CertFindCertificateInStore(
hSystemStore,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ ENCODING,
0,
- CERT_FIND_SUBJECT_NAME,
- pIssuer,
- IntPtr.Zero
+ CERT_FIND_FLAGS.CERT_FIND_SUBJECT_NAME,
+ &(pCertInfo->Issuer),
+ null
);
}
- Marshal.FreeHGlobal(pIssuer);
- if (pCurrContext == IntPtr.Zero)
+ if (pCurrContext is null)
return false;
- var pCurrPublicKey = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(certInfo.SubjectPublicKeyInfo, pCurrPublicKey, false);
-
- var origContext = Marshal.PtrToStructure(pOrigContext);
- var origInfo = Marshal.PtrToStructure(origContext.pCertInfo);
- var pOrigPublicKey = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(origInfo.SubjectPublicKeyInfo, pOrigPublicKey, false);
-
- var result = CertComparePublicKeyInfo(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- pCurrPublicKey,
- pOrigPublicKey
+ var result = PInvoke.CertComparePublicKeyInfo(
+ ENCODING,
+ &pCurrContext->pCertInfo->SubjectPublicKeyInfo,
+ &pOrigContext->pCertInfo->SubjectPublicKeyInfo
);
- Marshal.FreeHGlobal(pCurrPublicKey);
- Marshal.FreeHGlobal(pOrigPublicKey);
-
return !result;
}
- private static bool GetSignerCertificateInfo(string fileName, List signChain, CancellationToken ct)
+ private unsafe static bool GetSignerCertificateInfo(string fileName, List signChain, CancellationToken ct)
{
var succeded = false;
- var authSignData = new SignDataHandle();
+ var authSignData = new SignDataHandle() { dwObjSize = 0, hCertStoreHandle = HCERTSTORE.Null, pSignerInfo = null };
var signDataChain = new List();
signChain.Clear();
- var pRoot = Marshal.StringToHGlobalAuto("Root");
- var hSystemStore = CertOpenStore(
- CERT_STORE_PROV_SYSTEM,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- IntPtr.Zero,
- CERT_SYSTEM_STORE_CURRENT_USER,
+ var cert_store_prov_system = (PCSTR)(byte*)10;
+ var root = "Root";
+ var pRoot = &root;
+ var hSystemStore = PInvoke.CertOpenStore(
+ cert_store_prov_system,
+ ENCODING,
+ HCRYPTPROV_LEGACY.Null,
+ (CERT_OPEN_STORE_FLAGS)CERT_SYSTEM_STORE_CURRENT_USER,
pRoot
- );
- Marshal.FreeHGlobal(pRoot);
+ );
if (hSystemStore == IntPtr.Zero)
return false;
- var hAuthCryptMsg = IntPtr.Zero;
+ void* hAuthCryptMsg = null;
var result = TryGetSignerInfo(
fileName,
- ref hAuthCryptMsg,
- ref authSignData.hCertStoreHandle,
- ref authSignData.pSignerInfo,
- ref authSignData.dwObjSize
+ out hAuthCryptMsg,
+ out authSignData.hCertStoreHandle,
+ out authSignData.pSignerInfo,
+ out authSignData.dwObjSize
);
- if (hAuthCryptMsg != IntPtr.Zero)
+ if (hAuthCryptMsg is not null)
{
- CryptMsgClose(hAuthCryptMsg);
- hAuthCryptMsg = IntPtr.Zero;
+ PInvoke.CryptMsgClose(hAuthCryptMsg);
+ hAuthCryptMsg = null;
}
if (!result)
{
if (authSignData.hCertStoreHandle != IntPtr.Zero)
- CertCloseStore(authSignData.hCertStoreHandle, 0);
+ PInvoke.CertCloseStore(authSignData.hCertStoreHandle, 0);
- CertCloseStore(hSystemStore, 0);
+ PInvoke.CertCloseStore(hSystemStore, 0);
return false;
}
@@ -286,38 +257,37 @@ ref authSignData.dwObjSize
{
if (ct.IsCancellationRequested)
{
- CertCloseStore(hSystemStore, 0);
+ PInvoke.CertCloseStore(hSystemStore, 0);
return false;
}
- var pCurrContext = IntPtr.Zero;
- var pCounterSigner = IntPtr.Zero;
+ CERT_CONTEXT* pCurrContext = null;
+ CMSG_SIGNER_INFO* pCounterSigner = null;
var signNode = new SignNodeInfo();
- GetCounterSignerInfo(signDataChain[i].pSignerInfo, ref pCounterSigner);
- if (pCounterSigner != IntPtr.Zero)
+ GetCounterSignerInfo(signDataChain[i].pSignerInfo, &pCounterSigner);
+ if (pCounterSigner is not null)
GetCounterSignerData(pCounterSigner, signNode.CounterSign);
else
GetGeneralizedTimeStamp(signDataChain[i].pSignerInfo, signNode.CounterSign);
- var signerInfo = Marshal.PtrToStructure(signDataChain[i].pSignerInfo);
- var szObjId = signerInfo.HashAlgorithm.pszObjId;
+ var pszObjId = signDataChain[i].pSignerInfo->HashAlgorithm.pszObjId;
+ var szObjId = new string((sbyte*)(byte*)pszObjId);
CalculateDigestAlgorithm(szObjId, signNode);
- (_, signNode.Version) = CalculateSignVersion(signerInfo.dwVersion);
+ (_, signNode.Version) = CalculateSignVersion(signDataChain[i].pSignerInfo->dwVersion);
- var pIssuer = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(signerInfo.Issuer, pIssuer, false);
- pCurrContext = CertFindCertificateInStore(
+
+ var pIssuer = &(signDataChain[i].pSignerInfo->Issuer);
+ pCurrContext = PInvoke.CertFindCertificateInStore(
signDataChain[i].hCertStoreHandle,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
+ ENCODING,
0,
- CERT_FIND_ISSUER_NAME,
+ CERT_FIND_FLAGS.CERT_FIND_ISSUER_NAME,
pIssuer,
- IntPtr.Zero
+ null
);
- Marshal.FreeHGlobal(pIssuer);
- result = pCurrContext != IntPtr.Zero;
+ result = pCurrContext is not null;
while (result)
{
var pOrigContext = pCurrContext;
@@ -328,20 +298,20 @@ ref authSignData.dwObjSize
ref pCurrContext,
signNode
);
- CertFreeCertificateContext(pOrigContext);
+ PInvoke.CertFreeCertificateContext(pOrigContext);
}
- if (pCurrContext != IntPtr.Zero)
- CertFreeCertificateContext(pCurrContext);
+ if (pCurrContext is not null)
+ PInvoke.CertFreeCertificateContext(pCurrContext);
- if (pCounterSigner != IntPtr.Zero)
- Marshal.FreeHGlobal(pCounterSigner);
+ if (pCounterSigner is not null)
+ NativeMemory.Free(pCounterSigner);
- if (signDataChain[i].pSignerInfo != IntPtr.Zero)
- Marshal.FreeHGlobal(signDataChain[i].pSignerInfo);
+ if (signDataChain[i].pSignerInfo is not null)
+ NativeMemory.Free(signDataChain[i].pSignerInfo);
- if (signDataChain[i].hCertStoreHandle != IntPtr.Zero)
- CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
+ if (!signDataChain[i].hCertStoreHandle.IsNull)
+ PInvoke.CertCloseStore(signDataChain[i].hCertStoreHandle, 0);
succeded = true;
signNode.IsValid = VerifyySignature(fileName);
@@ -349,145 +319,151 @@ ref authSignData.dwObjSize
signChain.Add(signNode);
}
- CertCloseStore(hSystemStore, 0);
+ PInvoke.CertCloseStore(hSystemStore, 0);
return succeded;
}
- private static bool VerifyySignature(string certPath)
+ private unsafe static bool VerifyySignature(string certPath)
{
+ int res = 1;
+ var sFileInfo = (uint)Marshal.SizeOf();
+ var sData = (uint)Marshal.SizeOf();
var actionGuid = new Guid("{00AAC56B-CD44-11D0-8CC2-00C04FC295EE}");
- var guidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(actionGuid));
- Marshal.StructureToPtr(actionGuid, guidPtr, false);
- var sFileInfo = Marshal.SizeOf();
- var fileInfo = new WINTRUST_FILE_INFO
+ fixed (char* pCertPath = certPath)
{
- cbStruct = (uint)sFileInfo,
- pcwszFilePath = Marshal.StringToCoTaskMemAuto(certPath),
- hFile = IntPtr.Zero,
- pgKnownSubject = IntPtr.Zero
- };
- var filePtr = Marshal.AllocHGlobal(sFileInfo);
- Marshal.StructureToPtr(fileInfo, filePtr, false);
+ var fileInfo = new WINTRUST_FILE_INFO
+ {
+ cbStruct = sFileInfo,
+ pcwszFilePath = (PCWSTR)pCertPath,
+ hFile = (HANDLE)null,
+ pgKnownSubject = null
+ };
- var sData = Marshal.SizeOf();
- var wintrustData = new WINTRUST_DATA
- {
- cbStruct = (uint)sData,
- pPolicyCallbackData = IntPtr.Zero,
- pSIPClientData = IntPtr.Zero,
- dwUIChoice = 2, // Display no UI
- fdwRevocationChecks = 0, // No revocation checking
- dwUnionChoice = 1, // Verify an embedded signature on a file
- dwStateAction = 1, // Verify action
- hVWTStateData = IntPtr.Zero,
- pwszURLReference = IntPtr.Zero,
- dwUIContext = 0,
- pFile = filePtr
- };
- var dataPtr = Marshal.AllocHGlobal(sData);
- Marshal.StructureToPtr(wintrustData, dataPtr, false);
+ var wintrustData = new WINTRUST_DATA
+ {
+ cbStruct = sData,
+ pPolicyCallbackData = null,
+ pSIPClientData = null,
+ dwUIChoice = WINTRUST_DATA_UICHOICE.WTD_UI_NONE,
+ fdwRevocationChecks = 0, // No revocation checking
+ dwUnionChoice = WINTRUST_DATA_UNION_CHOICE.WTD_CHOICE_FILE,
+ dwStateAction = WINTRUST_DATA_STATE_ACTION.WTD_STATEACTION_VERIFY,
+ hWVTStateData = (HANDLE)null,
+ pwszURLReference = null,
+ dwUIContext = 0,
+ Anonymous = new WINTRUST_DATA._Anonymous_e__Union
+ {
+ pFile = &fileInfo,
+ },
+ };
- try
- {
- var res = WinVerifyTrust(IntPtr.Zero, guidPtr, dataPtr);
+ res = PInvoke.WinVerifyTrust((HWND)null, ref actionGuid, &wintrustData);
// Release hWVTStateData
- wintrustData.dwStateAction = 2; // Close
- Marshal.StructureToPtr(wintrustData, dataPtr, true);
- WinVerifyTrust(IntPtr.Zero, guidPtr, dataPtr);
-
- return res == 0;
+ wintrustData.dwStateAction = WINTRUST_DATA_STATE_ACTION.WTD_STATEACTION_CLOSE;
+ PInvoke.WinVerifyTrust((HWND)null, ref actionGuid, &wintrustData);
}
- finally
- {
- if (fileInfo.pcwszFilePath != IntPtr.Zero)
- Marshal.FreeCoTaskMem(fileInfo.pcwszFilePath);
- Marshal.FreeHGlobal(guidPtr);
- Marshal.FreeHGlobal(filePtr);
- Marshal.FreeHGlobal(dataPtr);
- }
+ return res == 0;
}
- private static bool TryGetSignerInfo(
+ private unsafe static bool TryGetSignerInfo(
string fileName,
- ref IntPtr hMsg,
- ref IntPtr hCertStore,
- ref IntPtr pSignerInfo,
- ref uint signerSize,
+ out void* hMsg,
+ out HCERTSTORE hCertStore,
+ out CMSG_SIGNER_INFO* pSignerInfo,
+ out uint signerSize,
uint index = 0)
{
- uint encoding = 0;
- var pDummy = IntPtr.Zero;
- uint dummy = 0;
- var pFileName = Marshal.StringToHGlobalAuto(fileName);
- var result = CryptQueryObject(
- CERT_QUERY_OBJECT_FILE,
- pFileName,
- CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
- CERT_QUERY_FORMAT_FLAG_BINARY,
- 0,
- ref encoding,
- ref dummy,
- ref dummy,
- ref hCertStore,
- ref hMsg,
- ref pDummy
- );
- Marshal.FreeHGlobal(pFileName);
+ CERT_QUERY_ENCODING_TYPE encoding = 0;
+ CERT_QUERY_CONTENT_TYPE dummy = 0;
+ CERT_QUERY_FORMAT_TYPE dummy2 = 0;
+ void* pDummy = null;
+ BOOL result = false;
+
+ HCERTSTORE hCertStoreTmp = HCERTSTORE.Null;
+ void* hMsgTmp = null;
+
+ fixed (char* pFileName = fileName)
+ {
+ result = PInvoke.CryptQueryObject(
+ CERT_QUERY_OBJECT_TYPE.CERT_QUERY_OBJECT_FILE,
+ pFileName,
+ CERT_QUERY_CONTENT_TYPE_FLAGS.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+ CERT_QUERY_FORMAT_TYPE_FLAGS.CERT_QUERY_FORMAT_FLAG_BINARY,
+ 0,
+ &encoding,
+ &dummy,
+ &dummy2,
+ &hCertStoreTmp,
+ &hMsgTmp,
+ &pDummy
+ );
+ }
+
+ hCertStore = hCertStoreTmp;
+ hMsg = hMsgTmp;
+ pSignerInfo = null;
+ signerSize = 0;
if (!result)
return false;
+ var vpSignerInfo = (void*)pSignerInfo;
result = CustomCryptMsgGetParam(
hMsg,
CMSG_SIGNER_INFO_PARAM,
index,
- ref pSignerInfo,
+ ref vpSignerInfo,
ref signerSize
);
+ pSignerInfo = (CMSG_SIGNER_INFO*)vpSignerInfo;
return result;
}
- private static bool GetCounterSignerInfo(IntPtr pSignerInfo, ref IntPtr pTargetSigner)
+ private unsafe static bool GetCounterSignerInfo(
+ CMSG_SIGNER_INFO* pSignerInfo,
+ CMSG_SIGNER_INFO** pTargetSigner)
{
uint objSize = 0;
- if (pSignerInfo == IntPtr.Zero)
+ if (pSignerInfo is null || pTargetSigner is null)
return false;
try
{
- var res = TryGetUnauthAttr(pSignerInfo, szOID_RSA_counterSign, out var attr);
- if (!res)
+ *pTargetSigner = null;
+ CRYPT_ATTRIBUTE* attr = null;
+ var res = TryGetUnauthAttr(pSignerInfo, szOID_RSA_counterSign, ref attr);
+ if (!res || attr is null)
return false;
- var rgValue = Marshal.PtrToStructure(attr.rgValue);
- var result = CryptDecodeObject(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- PKCS7_SIGNER_INFO,
- rgValue.pbData,
- rgValue.cbData,
+ var pkcs7_signer_info = (PCSTR)(byte*)500;
+ var result = PInvoke.CryptDecodeObject(
+ ENCODING,
+ pkcs7_signer_info,
+ attr->rgValue[0].pbData,
+ attr->rgValue[0].cbData,
0,
- IntPtr.Zero,
- ref objSize
+ null,
+ &objSize
);
if (!result)
return false;
- pTargetSigner = Marshal.AllocHGlobal((int)objSize * sizeof(byte));
- if (pTargetSigner == IntPtr.Zero)
+ *pTargetSigner = (CMSG_SIGNER_INFO*)NativeMemory.Alloc(objSize);
+ if (*pTargetSigner is null)
return false;
- result = CryptDecodeObject(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- PKCS7_SIGNER_INFO,
- rgValue.pbData,
- rgValue.cbData,
+ result = PInvoke.CryptDecodeObject(
+ ENCODING,
+ pkcs7_signer_info,
+ attr->rgValue[0].pbData,
+ attr->rgValue[0].cbData,
0,
- pTargetSigner,
- ref objSize
+ *pTargetSigner,
+ &objSize
);
if (!result)
return false;
@@ -499,57 +475,45 @@ ref objSize
return true;
}
- private static bool GetCounterSignerData(IntPtr pSignerInfo, SignCounterSign counterSign)
+ private unsafe static bool GetCounterSignerData(CMSG_SIGNER_INFO* pSignerInfo, SignCounterSign counterSign)
{
- var res = TryGetAuthAttr(pSignerInfo, szOID_RSA_signingTime, out var attr);
- if (!res)
+ CRYPT_ATTRIBUTE* attr = null;
+ var res = TryGetAuthAttr(pSignerInfo, szOID_RSA_signingTime, ref attr);
+ if (!res || attr is null)
return false;
- var rgValue = Marshal.PtrToStructure(attr.rgValue);
-
- var data = (uint)Marshal.SizeOf();
- var ft = Marshal.AllocHGlobal((int)data);
- IntPtr lft = IntPtr.Zero;
- IntPtr st = IntPtr.Zero;
-
+ var data = (uint)Marshal.SizeOf();
+ var ft = (System.Runtime.InteropServices.ComTypes.FILETIME*)NativeMemory.Alloc(data);
try
{
- var pStructType = Marshal.StringToHGlobalUni(szOID_RSA_signingTime);
- var result = CryptDecodeObject(
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- PKCS_UTC_TIME,
- rgValue.pbData,
- rgValue.cbData,
+ var pkcs_utc_time = (PCSTR)(byte*)17;
+ var result = PInvoke.CryptDecodeObject(
+ ENCODING,
+ pkcs_utc_time,
+ attr->rgValue[0].pbData,
+ attr->rgValue[0].cbData,
0,
ft,
- ref data
+ &data
);
- Marshal.FreeHGlobal(pStructType);
if (!result)
return false;
- lft = Marshal.AllocHGlobal((int)data);
- st = Marshal.AllocHGlobal(Marshal.SizeOf());
- FileTimeToLocalFileTime(ft, lft);
- FileTimeToSystemTime(lft, st);
- counterSign.TimeStamp = TimeToString(IntPtr.Zero, st);
+ PInvoke.FileTimeToLocalFileTime(*ft, out var lft);
+ PInvoke.FileTimeToSystemTime(lft, out var st);
+ counterSign.TimeStamp = TimeToString(null, &st);
return true;
}
finally
{
- Marshal.FreeHGlobal(ft);
- if (lft != IntPtr.Zero)
- Marshal.FreeHGlobal(lft);
-
- if (st != IntPtr.Zero)
- Marshal.FreeHGlobal(st);
+ NativeMemory.Free(ft);
}
}
- private static bool ParseDERFindType(
+ private unsafe static bool ParseDERFindType(
int typeSearch,
- IntPtr pbSignature,
+ byte* pbSignature,
uint size,
ref uint positionFound,
ref uint lengthFound)
@@ -561,7 +525,7 @@ private static bool ParseDERFindType(
var iClass = 0;
positionFound = 0;
lengthFound = 0;
- if (pbSignature == IntPtr.Zero)
+ if (pbSignature is null)
return false;
while (size > position)
@@ -569,12 +533,12 @@ private static bool ParseDERFindType(
if (!SafeToReadNBytes(size, position, 2))
return false;
- ParseDERType(Marshal.ReadByte(pbSignature, (int)position), ref iType, ref iClass);
+ ParseDERType(pbSignature[position], ref iType, ref iClass);
switch (iType)
{
case 0x05: // Null
++position;
- if (Marshal.ReadByte(pbSignature, (int)position) != 0x00)
+ if (pbSignature[position] != 0x00)
return false;
++position;
@@ -582,11 +546,10 @@ private static bool ParseDERFindType(
case 0x06: // Object Identifier
++position;
- var val = Marshal.ReadByte(pbSignature, (int)position);
- if (!SafeToReadNBytes(size - position, 1, val))
+ if (!SafeToReadNBytes(size - position, 1, pbSignature[position]))
return false;
- position += 1u + val;
+ position += 1u + pbSignature[position];
break;
case 0x00: // ?
@@ -604,10 +567,10 @@ private static bool ParseDERFindType(
case 0x1E: // BMPstring
++position;
if (!ParseDERSize(
- IntPtr.Add(pbSignature, (int)position),
- size - position,
- ref sizeFound,
- ref bytesParsed))
+ pbSignature + position,
+ size - position,
+ ref sizeFound,
+ ref bytesParsed))
{
return false;
}
@@ -635,10 +598,10 @@ private static bool ParseDERFindType(
case 0x31: // set
position++;
if (!ParseDERSize(
- IntPtr.Add(pbSignature, (int)position),
- size - position,
- ref sizeFound,
- ref bytesParsed))
+ pbSignature + position,
+ size - position,
+ ref sizeFound,
+ ref bytesParsed))
{
return false;
}
@@ -658,34 +621,34 @@ private static bool ParseDERFindType(
return false;
}
- private static bool GetGeneralizedTimeStamp(
- IntPtr pSignerInfo,
+ private unsafe static bool GetGeneralizedTimeStamp(
+ CMSG_SIGNER_INFO* pSignerInfo,
SignCounterSign counter)
{
uint positionFound = 0;
uint lengthFound = 0;
- var res = TryGetUnauthAttr(pSignerInfo, szOID_RFC3161_counterSign, out var attr);
- if (!res)
+ CRYPT_ATTRIBUTE* attr = null;
+ var res = TryGetUnauthAttr(pSignerInfo, szOID_RFC3161_counterSign, ref attr);
+ if (!res || attr is null)
return false;
- var rgValue = Marshal.PtrToStructure(attr.rgValue);
var result = ParseDERFindType(
0x04,
- rgValue.pbData,
- rgValue.cbData,
+ attr->rgValue[0].pbData,
+ attr->rgValue[0].cbData,
ref positionFound,
ref lengthFound);
if (!result)
return false;
// Counter Signer Timstamp
- var pbOctetString = IntPtr.Add(rgValue.pbData, (int)positionFound);
+ var pbOctetString = attr->rgValue[0].pbData + positionFound;
counter.TimeStamp = GetTimeStampFromDER(pbOctetString, lengthFound, ref positionFound);
return true;
}
- private static string GetTimeStampFromDER(IntPtr pbOctetString, uint lengthFound, ref uint positionFound)
+ private unsafe static string GetTimeStampFromDER(byte* pbOctetString, uint lengthFound, ref uint positionFound)
{
var result = ParseDERFindType(
0x18,
@@ -697,165 +660,151 @@ ref lengthFound
if (!result)
return string.Empty;
- var st = new SYSTEMTIME();
- var buffer = Marshal.PtrToStringUTF8(
- IntPtr.Add(pbOctetString, (int)positionFound),
- (int)lengthFound
- ) + (char)0;
-
- _ = short.TryParse(buffer.AsSpan(0, 4), out st.Year);
- _ = short.TryParse(buffer.AsSpan(4, 2), out st.Month);
- _ = short.TryParse(buffer.AsSpan(6, 2), out st.Day);
- _ = short.TryParse(buffer.AsSpan(8, 2), out st.Hour);
- _ = short.TryParse(buffer.AsSpan(10, 2), out st.Minute);
- _ = short.TryParse(buffer.AsSpan(12, 2), out st.Second);
- _ = short.TryParse(buffer.AsSpan(15, 3), out st.Milliseconds);
-
- var sst = Marshal.AllocHGlobal(Marshal.SizeOf());
- var lst = Marshal.AllocHGlobal(Marshal.SizeOf());
- var fft = Marshal.AllocHGlobal(Marshal.SizeOf());
- var lft = Marshal.AllocHGlobal(Marshal.SizeOf());
- Marshal.StructureToPtr(st, sst, true);
- SystemTimeToFileTime(sst, fft);
- FileTimeToLocalFileTime(fft, lft);
- FileTimeToSystemTime(lft, lst);
- var timestamp = TimeToString(IntPtr.Zero, lst);
-
- Marshal.FreeHGlobal(fft);
- Marshal.FreeHGlobal(lft);
- Marshal.FreeHGlobal(sst);
- Marshal.FreeHGlobal(lst);
+ var st = new Windows.Win32.Foundation.SYSTEMTIME();
+ var buffer = new string((sbyte*)(pbOctetString + positionFound));
+
+ _ = ushort.TryParse(buffer.AsSpan(0, 4), out st.wYear);
+ _ = ushort.TryParse(buffer.AsSpan(4, 2), out st.wMonth);
+ _ = ushort.TryParse(buffer.AsSpan(6, 2), out st.wDay);
+ _ = ushort.TryParse(buffer.AsSpan(8, 2), out st.wHour);
+ _ = ushort.TryParse(buffer.AsSpan(10, 2), out st.wMinute);
+ _ = ushort.TryParse(buffer.AsSpan(12, 2), out st.wSecond);
+ _ = ushort.TryParse(buffer.AsSpan(15, 3), out st.wMilliseconds);
+
+ PInvoke.SystemTimeToFileTime(st, out var fft);
+ PInvoke.FileTimeToLocalFileTime(fft, out var lft);
+ PInvoke.FileTimeToSystemTime(lft, out var lst);
+ var timestamp = TimeToString(null, &lst);
return timestamp;
}
- private static bool GetStringFromCertContext(IntPtr pCertContext, uint dwType, uint flag, CertNodeInfoItem info)
+ private unsafe static bool GetStringFromCertContext(CERT_CONTEXT* pCertContext, uint dwType, uint flag, CertNodeInfoItem info)
{
- var data = CertGetNameStringA(pCertContext, dwType, flag, IntPtr.Zero, IntPtr.Zero, 0);
+ var data = CertGetNameStringA(pCertContext, dwType, flag, null, (PCSTR)null, 0);
if (data == 0)
{
- CertFreeCertificateContext(pCertContext);
+ PInvoke.CertFreeCertificateContext(pCertContext);
return false;
}
- var pszTempName = Marshal.AllocHGlobal((int)data * sizeof(byte));
- if (pszTempName == IntPtr.Zero)
+ var pszTempName = (PCSTR)NativeMemory.Alloc(data);
+ if (pszTempName.Value is null)
{
- CertFreeCertificateContext(pCertContext);
+ PInvoke.CertFreeCertificateContext(pCertContext);
return false;
}
- data = CertGetNameStringA(pCertContext, dwType, flag, IntPtr.Zero, pszTempName, data);
+ data = CertGetNameStringA(pCertContext, dwType, flag, null, pszTempName, data);
if (data == 0)
{
- Marshal.FreeHGlobal(pszTempName);
+ NativeMemory.Free(pszTempName);
return false;
}
+ var tmpName = new string((sbyte*)(byte*)pszTempName);
if (flag == 0)
- info.IssuedTo = StripString(Marshal.PtrToStringUTF8(pszTempName));
+ info.IssuedTo = StripString(tmpName);
else
- info.IssuedBy = StripString(Marshal.PtrToStringUTF8(pszTempName));
+ info.IssuedBy = StripString(tmpName);
- Marshal.FreeHGlobal(pszTempName);
+ NativeMemory.Free(pszTempName);
return true;
}
- private static bool TryGetUnauthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
+ private unsafe static bool TryGetUnauthAttr(CMSG_SIGNER_INFO* pSignerInfo, string oid, ref CRYPT_ATTRIBUTE* attr)
{
int n = 0;
- var signerInfo = Marshal.PtrToStructure(pSignerInfo);
- attr = new CRYPT_ATTRIBUTE();
- for (; n < signerInfo.UnauthAttrs.cbData; n++)
+ attr = null;
+ for (; n < pSignerInfo->UnauthAttrs.cAttr; n++)
{
- attr = Marshal.PtrToStructure(
- IntPtr.Add(signerInfo.UnauthAttrs.pbData, n * Marshal.SizeOf())
- );
- if (attr.pszObjId == oid)
+ attr = &pSignerInfo->UnauthAttrs.rgAttr[n];
+ var objId = new string((sbyte*)(byte*)attr->pszObjId);
+ if (objId == oid)
break;
}
- return n < signerInfo.UnauthAttrs.cbData;
+ return n < pSignerInfo->UnauthAttrs.cAttr;
}
- private static bool TryGetAuthAttr(IntPtr pSignerInfo, string oid, out CRYPT_ATTRIBUTE attr)
+ private unsafe static bool TryGetAuthAttr(CMSG_SIGNER_INFO* pSignerInfo, string oid, ref CRYPT_ATTRIBUTE* attr)
{
int n = 0;
- var signerInfo = Marshal.PtrToStructure(pSignerInfo);
- attr = new CRYPT_ATTRIBUTE();
- for (; n < signerInfo.AuthAttrs.cbData; n++)
+ attr = null;
+ for (; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
- attr = Marshal.PtrToStructure(
- IntPtr.Add(signerInfo.AuthAttrs.pbData, n * Marshal.SizeOf())
- );
- if (attr.pszObjId == oid)
+ attr = &pSignerInfo->AuthAttrs.rgAttr[n];
+ var objId = new string((sbyte*)(byte*)attr->pszObjId);
+ if (objId == oid)
break;
}
- return n < signerInfo.AuthAttrs.cbData;
+ return n < pSignerInfo->AuthAttrs.cAttr;
}
- private static bool GetNestedSignerInfo(ref SignDataHandle AuthSignData, List NestedChain)
+ private unsafe static bool GetNestedSignerInfo(ref SignDataHandle AuthSignData, List NestedChain)
{
var succeded = false;
- var hNestedMsg = IntPtr.Zero;
- if (AuthSignData.pSignerInfo == IntPtr.Zero)
+ void* hNestedMsg = null;
+ if (AuthSignData.pSignerInfo is null)
return false;
try
{
- var res = TryGetUnauthAttr(AuthSignData.pSignerInfo, szOID_NESTED_SIGNATURE, out var attr);
- if (!res)
+ CRYPT_ATTRIBUTE* attr = null;
+ var res = TryGetUnauthAttr(AuthSignData.pSignerInfo, szOID_NESTED_SIGNATURE, ref attr);
+ if (!res || attr is null)
return false;
- var rgValue = Marshal.PtrToStructure(attr.rgValue);
- var cbCurrData = rgValue.cbData;
- var pbCurrData = rgValue.pbData;
-
- var upperBound = IntPtr.Add(AuthSignData.pSignerInfo, (int)AuthSignData.dwObjSize);
+ var cbCurrData = attr->rgValue[0].cbData;
+ var pbCurrData = attr->rgValue[0].pbData;
+ var upperBound = AuthSignData.pSignerInfo + AuthSignData.dwObjSize;
while (pbCurrData > AuthSignData.pSignerInfo && pbCurrData < upperBound)
{
- var nestedHandle = new SignDataHandle() { dwObjSize = 0 };
+ var nestedHandle = new SignDataHandle() { dwObjSize = 0, pSignerInfo = null, hCertStoreHandle = HCERTSTORE.Null };
if (!Memcmp(pbCurrData, SG_ProtoCoded) ||
- !Memcmp(IntPtr.Add(pbCurrData, 6), SG_SignedData))
+ !Memcmp(pbCurrData + 6, SG_SignedData))
{
break;
}
- hNestedMsg = CryptMsgOpenToDecode(
+ hNestedMsg = PInvoke.CryptMsgOpenToDecode(
PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
0,
0,
- IntPtr.Zero,
- IntPtr.Zero,
- IntPtr.Zero
+ HCRYPTPROV_LEGACY.Null,
+ null,
+ null
);
- if (hNestedMsg == IntPtr.Zero)
+ if (hNestedMsg is null)
return false;
- cbCurrData = XCHWordLitend(unchecked((ushort)Marshal.ReadInt16(pbCurrData)) + 2u) + 4u;
+ cbCurrData = XCHWordLitend(*(ushort*)(pbCurrData + 2)) + 4u;
var pbNextData = pbCurrData;
- pbNextData = IntPtr.Add(pbNextData, (int)EightByteAlign(cbCurrData, unchecked(pbCurrData)));
- var result = CryptMsgUpdate(hNestedMsg, pbCurrData, cbCurrData, true);
+ pbNextData += EightByteAlign(cbCurrData, (long)pbCurrData);
+ var result = PInvoke.CryptMsgUpdate(hNestedMsg, pbCurrData, cbCurrData, true);
pbCurrData = pbNextData;
if (!result)
continue;
+ var pSignerInfo = (void*)nestedHandle.pSignerInfo;
result = CustomCryptMsgGetParam(
hNestedMsg,
CMSG_SIGNER_INFO_PARAM,
0,
- ref nestedHandle.pSignerInfo,
+ ref pSignerInfo,
ref nestedHandle.dwObjSize
);
+ nestedHandle.pSignerInfo = (CMSG_SIGNER_INFO*)pSignerInfo;
if (!result)
continue;
- nestedHandle.hCertStoreHandle = CertOpenStore(
- CERT_STORE_PROV_MSG,
- PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
- IntPtr.Zero,
+ var cert_store_prov_msg = (PCSTR)(byte*)1;
+ nestedHandle.hCertStoreHandle = PInvoke.CertOpenStore(
+ cert_store_prov_msg,
+ ENCODING,
+ HCRYPTPROV_LEGACY.Null,
0,
hNestedMsg
);
@@ -866,38 +815,38 @@ ref nestedHandle.dwObjSize
}
finally
{
- if (hNestedMsg != IntPtr.Zero)
- CryptMsgClose(hNestedMsg);
+ if (hNestedMsg is not null)
+ PInvoke.CryptMsgClose(hNestedMsg);
}
return succeded;
}
- private static bool CustomCryptMsgGetParam(
- IntPtr hCryptMsg,
+ private unsafe static bool CustomCryptMsgGetParam(
+ void* hCryptMsg,
uint paramType,
uint index,
- ref IntPtr pParam,
+ ref void* pParam,
ref uint outSize)
{
bool result;
uint size = 0;
- result = CryptMsgGetParam(
+ result = PInvoke.CryptMsgGetParam(
hCryptMsg,
paramType,
index,
- IntPtr.Zero,
+ null,
ref size
);
if (!result)
return false;
- pParam = Marshal.AllocHGlobal((int)size);
- if (pParam == IntPtr.Zero)
+ pParam = NativeMemory.Alloc(size);
+ if (pParam is null)
return false;
- result = CryptMsgGetParam(
+ result = PInvoke.CryptMsgGetParam(
hCryptMsg,
paramType,
index,
@@ -917,11 +866,11 @@ private static ushort XCHWordLitend(uint num)
private static long EightByteAlign(long offset, long b)
=> ((offset + b + 7) & 0xFFFFFFF8L) - (b & 0xFFFFFFF8L);
- private static bool Memcmp(IntPtr ptr1, byte[] arr)
+ private unsafe static bool Memcmp(byte* ptr1, byte[] arr)
{
for (var i = 0; i < arr.Length; i++)
{
- if (Marshal.ReadByte(ptr1, i) != arr[i])
+ if (ptr1[i] != arr[i])
return false;
}
@@ -965,30 +914,29 @@ private static void ParseDERType(byte bIn, ref int iType, ref int iClass)
iClass = bIn >> 6;
}
- private static uint ReadNumberFromNBytes(IntPtr pbSignature, uint start, uint requestSize)
+ private unsafe static uint ReadNumberFromNBytes(byte* pbSignature, uint start, uint requestSize)
{
uint number = 0;
for (var i = 0; i < requestSize; i++)
- number = number * 0x100 + Marshal.ReadByte(pbSignature, (int)(start + i));
+ number = number * 0x100 + pbSignature[start + i];
return number;
}
- private static bool ParseDERSize(IntPtr pbSignature, uint size, ref uint sizeFound, ref uint bytesParsed)
+ private unsafe static bool ParseDERSize(byte* pbSignature, uint size, ref uint sizeFound, ref uint bytesParsed)
{
- var val = Marshal.ReadByte(pbSignature);
- if (val > 0x80 && !SafeToReadNBytes(size, 1, val - 0x80u))
+ if (pbSignature[0] > 0x80 && !SafeToReadNBytes(size, 1, pbSignature[0] - 0x80u))
return false;
- if (val <= 0x80)
+ if (pbSignature[0] <= 0x80)
{
- sizeFound = val;
+ sizeFound = pbSignature[0];
bytesParsed = 1;
}
else
{
- sizeFound = ReadNumberFromNBytes(pbSignature, 1, val - 0x80u);
- bytesParsed = val - 0x80u + 1;
+ sizeFound = ReadNumberFromNBytes(pbSignature, 1, pbSignature[0] - 0x80u);
+ bytesParsed = pbSignature[0] - 0x80u + 1;
}
return true;
@@ -1003,21 +951,22 @@ private static string StripString(string? str)
.Replace(((char)0).ToString(), "") ?? string.Empty;
}
- private static string TimeToString(IntPtr pftIn, IntPtr pstIn = 0)
+ private unsafe static string TimeToString(
+ System.Runtime.InteropServices.ComTypes.FILETIME* pftIn,
+ Windows.Win32.Foundation.SYSTEMTIME* pstIn = null)
{
- if (pstIn == IntPtr.Zero)
+ if (pstIn is null)
{
- if (pftIn == IntPtr.Zero)
+ if (pftIn is null)
return string.Empty;
- pstIn = Marshal.AllocHGlobal(Marshal.SizeOf());
- FileTimeToSystemTime(pftIn, pstIn);
+ PInvoke.FileTimeToSystemTime(*pftIn, out var sysTime);
+ pstIn = &sysTime;
}
- var st = Marshal.PtrToStructure(pstIn);
var date = new DateTime(
- st.Year, st.Month, st.Day,
- st.Hour, st.Minute, st.Second
+ pstIn->wYear, pstIn->wMonth, pstIn->wDay,
+ pstIn->wHour, pstIn->wMinute, pstIn->wSecond
);
return formatter.ToLongLabel(date);
@@ -1035,7 +984,7 @@ class SignNodeInfo
public string Version { get; set; } = string.Empty;
public int Index { get; set; } = 0;
public SignCounterSign CounterSign { get; set; } = new();
- public List CertChain = [];
+ public List CertChain { get; set; } = [];
}
}
}
diff --git a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
index 92e696953c4f..4dc1200a76e0 100644
--- a/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
+++ b/src/Files.App/ViewModels/Properties/SignaturesViewModel.cs
@@ -3,6 +3,7 @@
using Files.App.Utils.Signatures;
using Microsoft.UI.Windowing;
+using Windows.Win32.Foundation;
namespace Files.App.ViewModels.Properties
{
@@ -18,7 +19,7 @@ public SignaturesViewModel(ListedItem item, AppWindow appWindow)
{
_cancellationTokenSource = new();
Signatures = new();
- var hWnd = Microsoft.UI.Win32Interop.GetWindowFromWindowId(appWindow.Id);
+ var hWnd = new HWND(Microsoft.UI.Win32Interop.GetWindowFromWindowId(appWindow.Id));
Signatures.CollectionChanged += (s, e) => OnPropertyChanged(nameof(NoSignatureFound));
DigitalSignaturesUtil.LoadItemSignatures(
item.ItemPath,
From ba58d074430cdf8a7be1f3b73217a9384886584b Mon Sep 17 00:00:00 2001
From: Filippo Ferrario <102259289+ferrariofilippo@users.noreply.github.com>
Date: Wed, 30 Jul 2025 13:57:34 +0200
Subject: [PATCH 09/10] Library reference and methods
---
src/Files.App.CsWin32/NativeMethods.txt | 1 +
.../Helpers/Win32/Win32PInvoke.Methods.cs | 12 ------------
.../Utils/Signatures/DigitalSignaturesUtil.cs | 16 ++++++++--------
.../ViewModels/Settings/AboutViewModel.cs | 1 +
src/Files.App/Views/Settings/AboutPage.xaml | 2 +-
5 files changed, 11 insertions(+), 21 deletions(-)
diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt
index cec0a27850aa..a758d0ef4c51 100644
--- a/src/Files.App.CsWin32/NativeMethods.txt
+++ b/src/Files.App.CsWin32/NativeMethods.txt
@@ -268,3 +268,4 @@ WINTRUST_DATA
HCERTSTORE
HCRYPTMSG
CERT_QUERY_ENCODING_TYPE
+CertGetNameString
diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
index 1b9eeecd7c47..e52a08638811 100644
--- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
+++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs
@@ -5,7 +5,6 @@
using System.Runtime.InteropServices;
using System.Text;
using Windows.Win32.Foundation;
-using Windows.Win32.Security.Cryptography;
using Windows.Win32.System.Com;
namespace Files.App.Helpers
@@ -348,17 +347,6 @@ public static extern int SHGetKnownFolderPath(
out IntPtr pszPath
);
- // crypt32.dll
- [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
- public unsafe static extern uint CertGetNameStringA(
- CERT_CONTEXT* pCertContext,
- uint dwType,
- uint dwFlags,
- void* pvTypePara,
- PCSTR pszNameString,
- uint cchNameString
- );
-
// cryptui.dll
[DllImport("cryptui.dll", SetLastError = true, CharSet = CharSet.Auto)]
public unsafe static extern bool CryptUIDlgViewSignerInfo(CRYPTUI_VIEWSIGNERINFO_STRUCT* pViewInfo);
diff --git a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
index 0d4386b5412b..2c6a15b19bb1 100644
--- a/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
+++ b/src/Files.App/Utils/Signatures/DigitalSignaturesUtil.cs
@@ -681,34 +681,34 @@ ref lengthFound
private unsafe static bool GetStringFromCertContext(CERT_CONTEXT* pCertContext, uint dwType, uint flag, CertNodeInfoItem info)
{
- var data = CertGetNameStringA(pCertContext, dwType, flag, null, (PCSTR)null, 0);
+ var data = PInvoke.CertGetNameString(pCertContext, dwType, flag, null, (PWSTR)null, 0);
if (data == 0)
{
PInvoke.CertFreeCertificateContext(pCertContext);
return false;
}
- var pszTempName = (PCSTR)NativeMemory.Alloc(data);
+ var pszTempName = (PWSTR)NativeMemory.Alloc(data * sizeof(char));
if (pszTempName.Value is null)
{
PInvoke.CertFreeCertificateContext(pCertContext);
+ NativeMemory.Free(pszTempName);
return false;
}
- data = CertGetNameStringA(pCertContext, dwType, flag, null, pszTempName, data);
+ data = PInvoke.CertGetNameString(pCertContext, dwType, flag, null, pszTempName, data);
if (data == 0)
{
NativeMemory.Free(pszTempName);
return false;
}
- var tmpName = new string((sbyte*)(byte*)pszTempName);
+ var name = pszTempName.AsSpan().ToString();
+ NativeMemory.Free(pszTempName);
if (flag == 0)
- info.IssuedTo = StripString(tmpName);
+ info.IssuedTo = StripString(name);
else
- info.IssuedBy = StripString(tmpName);
-
- NativeMemory.Free(pszTempName);
+ info.IssuedBy = StripString(name);
return true;
}
diff --git a/src/Files.App/ViewModels/Settings/AboutViewModel.cs b/src/Files.App/ViewModels/Settings/AboutViewModel.cs
index 13ae41d4f00b..e84cc061182a 100644
--- a/src/Files.App/ViewModels/Settings/AboutViewModel.cs
+++ b/src/Files.App/ViewModels/Settings/AboutViewModel.cs
@@ -79,6 +79,7 @@ public AboutViewModel()
new ("https://github.com/microsoft/CsWinRT", "CsWinRT"),
new ("https://github.com/GihanSoft/NaturalStringComparer", "NaturalStringComparer"),
new ("https://github.com/dongle-the-gadget/GuidRVAGen", "Dongle.GuidRVAGen"),
+ new ("https://github.com/leeqwind/PESignAnalyzer", "PESignAnalyzer"),
];
CopyAppVersionCommand = new RelayCommand(CopyAppVersion);
diff --git a/src/Files.App/Views/Settings/AboutPage.xaml b/src/Files.App/Views/Settings/AboutPage.xaml
index 52a8b3eb841e..aa9f30a7ec96 100644
--- a/src/Files.App/Views/Settings/AboutPage.xaml
+++ b/src/Files.App/Views/Settings/AboutPage.xaml
@@ -188,7 +188,7 @@
Date: Wed, 30 Jul 2025 17:02:18 +0200
Subject: [PATCH 10/10] Move to helper
---
.../PropertiesNavigationViewItemFactory.cs | 19 ++++--------
.../Helpers/FileExtensionHelpers.cs | 29 +++++++++++++++++++
2 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
index 68ee970dcd5c..0723f321df0d 100644
--- a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
+++ b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
@@ -3,25 +3,12 @@
using Files.Shared.Helpers;
using Microsoft.UI.Xaml;
-using System.Collections.Frozen;
using Windows.Storage;
namespace Files.App.Data.Factories
{
public static class PropertiesNavigationViewItemFactory
{
- private static readonly FrozenSet _signableTypes = new HashSet()
- {
- ".aab", ".apk", ".application", ".appx", ".appxbundle", ".arx", ".cab", ".cat", ".cbx",
- ".cpl", ".crx", ".dbx", ".deploy", ".dll", ".doc", ".docm", ".dot", ".dotm", ".drx",
- ".ear", ".efi", ".exe", ".jar", ".js", ".manifest", ".mpp", ".mpt", ".msi", ".msix",
- ".msixbundle", ".msm", ".msp", ".nupkg", ".ocx", ".pot", ".potm", ".ppa", ".ppam", ".pps",
- ".ppsm", ".ppt", ".pptm", ".ps1", ".psm1", ".psi", ".pub", ".sar", ".stl", ".sys", ".vbs",
- ".vdw", ".vdx", ".vsd", ".vsdm", ".vss", ".vssm", ".vst", ".vstm", ".vsto", ".vsix", ".vsx", ".vtx",
- ".vxd", ".war", ".wiz", ".wsf", ".xap", ".xla", ".xlam", ".xls", ".xlsb", ".xlsm", ".xlt",
- ".xltm", ".xlsm", ".xsn"
- }.ToFrozenSet();
-
public static ObservableCollection Initialize(object item)
{
ObservableCollection PropertiesNavigationViewItems = [];
@@ -123,7 +110,11 @@ public static ObservableCollection Initialize
var detailsItemEnabled = !(isFolder && !listedItem.IsArchive) && !isLibrary && !listedItem.IsRecycleBinItem;
var customizationItemEnabled = !isLibrary && (isFolder && !listedItem.IsArchive || isShortcut && !listedItem.IsLinkItem);
var compatibilityItemEnabled = FileExtensionHelpers.IsExecutableFile(listedItem is IShortcutItem sht ? sht.TargetPath : fileExt, true);
- var signaturesItemEnabled = !isFolder && !isLibrary && !listedItem.IsRecycleBinItem && _signableTypes.Contains(fileExt);
+ var signaturesItemEnabled =
+ !isFolder &&
+ !isLibrary &&
+ !listedItem.IsRecycleBinItem &&
+ FileExtensionHelpers.IsSignableFile(fileExt, true);
if (!securityItemEnabled)
PropertiesNavigationViewItems.Remove(securityItem);
diff --git a/src/Files.Shared/Helpers/FileExtensionHelpers.cs b/src/Files.Shared/Helpers/FileExtensionHelpers.cs
index 970a3f777292..f23ebda8029d 100644
--- a/src/Files.Shared/Helpers/FileExtensionHelpers.cs
+++ b/src/Files.Shared/Helpers/FileExtensionHelpers.cs
@@ -2,6 +2,8 @@
// Licensed under the MIT License.
using System;
+using System.Collections.Frozen;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -12,6 +14,18 @@ namespace Files.Shared.Helpers
///
public static class FileExtensionHelpers
{
+ private static readonly FrozenSet _signableTypes = new HashSet()
+ {
+ ".aab", ".apk", ".application", ".appx", ".appxbundle", ".arx", ".cab", ".cat", ".cbx",
+ ".cpl", ".crx", ".dbx", ".deploy", ".dll", ".doc", ".docm", ".dot", ".dotm", ".drx",
+ ".ear", ".efi", ".exe", ".jar", ".js", ".manifest", ".mpp", ".mpt", ".msi", ".msix",
+ ".msixbundle", ".msm", ".msp", ".nupkg", ".ocx", ".pot", ".potm", ".ppa", ".ppam", ".pps",
+ ".ppsm", ".ppt", ".pptm", ".ps1", ".psm1", ".psi", ".pub", ".sar", ".stl", ".sys", ".vbs",
+ ".vdw", ".vdx", ".vsd", ".vsdm", ".vss", ".vssm", ".vst", ".vstm", ".vsto", ".vsix", ".vsx", ".vtx",
+ ".vxd", ".war", ".wiz", ".wsf", ".xap", ".xla", ".xlam", ".xls", ".xlsb", ".xlsm", ".xlt",
+ ".xltm", ".xlsm", ".xsn"
+ }.ToFrozenSet();
+
///
/// Check if the file extension matches one of the specified extensions.
///
@@ -273,5 +287,20 @@ public static bool IsSystemFile(string? filePathToCheck)
return HasExtension(filePathToCheck, ".dll", ".exe", ".sys", ".inf");
}
+ ///
+ /// Check if the file is signable.
+ ///
+ ///
+ /// true if the filePathToCheck is a signable file; otherwise, false.
+ public static bool IsSignableFile(string? filePathToCheck, bool isExtension = false)
+ {
+ if (string.IsNullOrWhiteSpace(filePathToCheck))
+ return false;
+
+ if (!isExtension)
+ filePathToCheck = Path.GetExtension(filePathToCheck);
+
+ return _signableTypes.Contains(filePathToCheck);
+ }
}
}