Calling CryptUIWizDigitalSign from .NET on x64

Posted by Joe Kuemerle on Stack Overflow See other posts from Stack Overflow or by Joe Kuemerle
Published on 2010-05-17T14:32:53Z Indexed on 2010/05/18 12:40 UTC
Read the original article Hit count: 211

Filed under:
|
|
|
|

I am trying to digitally sign files using the CryptUIWizDigitalSign function from a .NET 2.0 application compiled to AnyCPU. The call works fine when running on x86 but fails on x64, it also works on an x64 OS when compiled to x86. Any idea on how to better marshall or call from x64?

The Win32exception returned is "Error encountered during digital signing of the file ..." with a native error code of -2146762749.

The relevant portion of the code are:

[StructLayout(LayoutKind.Sequential)]
 public struct CRYPTUI_WIZ_DIGITAL_SIGN_INFO {
 public Int32 dwSize;
 public Int32 dwSubjectChoice;
 [MarshalAs(UnmanagedType.LPWStr)]
 public string pwszFileName;
 public Int32 dwSigningCertChoice;
 public IntPtr pSigningCertContext;
 [MarshalAs(UnmanagedType.LPWStr)]
 public string pwszTimestampURL;
 public Int32 dwAdditionalCertChoice;
 public IntPtr pSignExtInfo;
}

[DllImport("Cryptui.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern bool CryptUIWizDigitalSign(int dwFlags, IntPtr hwndParent, string pwszWizardTitle, ref CRYPTUI_WIZ_DIGITAL_SIGN_INFO pDigitalSignInfo, ref IntPtr ppSignContext);

CRYPTUI_WIZ_DIGITAL_SIGN_INFO digitalSignInfo = new CRYPTUI_WIZ_DIGITAL_SIGN_INFO();
digitalSignInfo = new CRYPTUI_WIZ_DIGITAL_SIGN_INFO();
digitalSignInfo.dwSize = Marshal.SizeOf(digitalSignInfo);
digitalSignInfo.dwSubjectChoice = 1;
digitalSignInfo.dwSigningCertChoice = 1;
digitalSignInfo.pSigningCertContext = pSigningCertContext;
digitalSignInfo.pwszTimestampURL = timestampUrl;
digitalSignInfo.dwAdditionalCertChoice = 0;
digitalSignInfo.pSignExtInfo = IntPtr.Zero;
digitalSignInfo.pwszFileName = filepath;
CryptUIWizDigitalSign(1, IntPtr.Zero, null, ref digitalSignInfo, ref pSignContext));

And here is how the SigningCertContext is retrieved (minus various error handling)

public IntPtr GetCertContext(String pfxfilename, String pswd)
 IntPtr hMemStore = IntPtr.Zero;
 IntPtr hCertCntxt = IntPtr.Zero;
 IntPtr pProvInfo = IntPtr.Zero;
 uint provinfosize = 0;
 try {                
  byte[] pfxdata = PfxUtility.GetFileBytes(pfxfilename);
  CRYPT_DATA_BLOB ppfx = new CRYPT_DATA_BLOB();
  ppfx.cbData = pfxdata.Length;
  ppfx.pbData = Marshal.AllocHGlobal(pfxdata.Length);
  Marshal.Copy(pfxdata, 0, ppfx.pbData, pfxdata.Length);
  hMemStore = Win32.PFXImportCertStore(ref ppfx, pswd, CRYPT_USER_KEYSET);
  pswd = null;
  if (hMemStore != IntPtr.Zero) {
   Marshal.FreeHGlobal(ppfx.pbData);
   while ((hCertCntxt = Win32.CertEnumCertificatesInStore(hMemStore, hCertCntxt)) != IntPtr.Zero) {
    if (Win32.CertGetCertificateContextProperty(hCertCntxt, CERT_KEY_PROV_INFO_PROP_ID, IntPtr.Zero, ref provinfosize))
     pProvInfo = Marshal.AllocHGlobal((int)provinfosize);
    else
     continue;
    if (Win32.CertGetCertificateContextProperty(hCertCntxt, CERT_KEY_PROV_INFO_PROP_ID, pProvInfo, ref provinfosize))
     break;
   }               
  }
finally {
 if (pProvInfo != IntPtr.Zero)
  Marshal.FreeHGlobal(pProvInfo);
 if (hMemStore != IntPtr.Zero)
  Win32.CertCloseStore(hMemStore, 0);
}
 return hCertCntxt;
}

© Stack Overflow or respective owner

Related posts about c#

Related posts about x64