Hi!
I have a problem using the CryptUIWizDigitalSign-Function in C#.
If I pass a file via CRYPTUI_WIZ_DIGITAL_SIGN_INFO-Structure that cannot be signed (i.e. Text-File), the function fails.
But if i try to delete the file after the failure, the file is locked until the process ends.
It the operation succeeds, the file is freed and everything is OK.
So the question is: how can I free the file, when the function fails?
using System.Runtime.InteropServices;
using System.ComponentModel;
using System;
using System.Security.Cryptography.X509Certificates;
namespace SignToolNet
{
public class Program
{
public const int CRYPTUI_WIZ_NO_UI = 1;
public const int CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE = 1;
public const int CRYPTUI_WIZ_DIGITAL_SIGN_CERT = 1;
public const int CRYPTUI_WIZ_DIGITAL_SIGN_COMMERCIAL = 1;
[StructLayout(LayoutKind.Sequential)]
public struct CRYPTUI_WIZ_DIGITAL_SIGN_INFO
{
public int dwSize;
public int dwSubjectChoice;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwszFileName;
public int dwSigningCertChoice;
public IntPtr pSigningCertContext;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwszTimestampURL;
public int dwAdditionalCertChoice;
public IntPtr pSignExtInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct CRYPTUI_WIZ_DIGITAL_SIGN_EXTENDED_INFO
{
public int dwSize;
public int dwAttrFlags;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwszDescription;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwszMoreInfoLocation;
[MarshalAs(UnmanagedType.LPStr)]
public string pszHashAlg;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwszSigningCertDisplayString;
public IntPtr hAdditionalCertStore;
public IntPtr psAuthenticated;
public IntPtr psUnauthenticated;
}
[StructLayout(LayoutKind.Sequential)]
public struct CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT
{
public int dwSize;
public int cbBlob;
public IntPtr pbBlob;
}
[DllImport("Cryptui.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CryptUIWizDigitalSign(
int dwFlags,
IntPtr hwndParent,
[MarshalAs(UnmanagedType.LPWStr)]
string pwszWizardTitle,
ref CRYPTUI_WIZ_DIGITAL_SIGN_INFO pDigitalSignInfo,
ref IntPtr ppSignContext);
[DllImport("Cryptui.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptUIWizFreeDigitalSignContext(IntPtr pSignContext);
public static void Main(string[] args)
{
string fileToSign = "d:\\test.txt";
string certThumbprint = "cert";
string timestampUrl = "http://timestamp.comodoca.com";
try
{
if (!System.IO.File.Exists(fileToSign)) return;
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var list = store.Certificates.Find(X509FindType.FindByThumbprint, certThumbprint, false);
if (list.Count == 0) return;
var cert = list[0];
var digitalSignInfo = new CRYPTUI_WIZ_DIGITAL_SIGN_INFO();
digitalSignInfo.dwSize = Marshal.SizeOf(digitalSignInfo);
digitalSignInfo.dwSubjectChoice = CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE;
digitalSignInfo.pwszFileName = fileToSign;
digitalSignInfo.dwSigningCertChoice = CRYPTUI_WIZ_DIGITAL_SIGN_CERT;
digitalSignInfo.pSigningCertContext = cert.Handle;
digitalSignInfo.pwszTimestampURL = timestampUrl;
digitalSignInfo.dwAdditionalCertChoice = 0;
digitalSignInfo.pSignExtInfo = IntPtr.Zero;
IntPtr psignContext = IntPtr.Zero;
try
{
IntPtr pSignContext = IntPtr.Zero;
bool result = CryptUIWizDigitalSign(CRYPTUI_WIZ_NO_UI, IntPtr.Zero, string.Empty, ref digitalSignInfo, ref pSignContext);
if (pSignContext!=IntPtr.Zero && !CryptUIWizFreeDigitalSignContext(pSignContext))
throw new Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizFreeDigitalSignContext");
if (!result)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
Marshal.FreeHGlobal(digitalSignInfo.pSignExtInfo);
}
}
catch (Win32Exception ex)
{
Console.WriteLine(string.Format("{0} {1:x}", ex.Message, ex.NativeErrorCode));
Environment.Exit(1);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Environment.Exit(1);
}
}
}
}
I am running Windows 10 1909 Build 18363.959 and Windows Server 2019 1809 Build 17763.1339.
Cheers
Alex