在 x64 上从 .NET 调用 CryptUIWizDigitalSign

发布于 2024-09-01 16:02:36 字数 2843 浏览 3 评论 0原文

我正在尝试使用编译到 AnyCPU 的 .NET 2.0 应用程序中的 CryptUIWizDigitalSign 函数对文件进行数字签名。该调用在 x86 上运行时工作正常,但在 x64 上运行失败,当编译为 x86 时,它也可以在 x64 操作系统上工作。关于如何更好地从 x64 编组或调用有什么想法吗?

返回的 Win32 异常是“文件数字签名期间遇到错误...”,本机错误代码为 -2146762749。

代码的相关部分是:

[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));

以下是如何检索 SigningCertContext(减去各种错误处理)

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;
}

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

再浓的妆也掩不了殇 2024-09-08 16:02:36

当使用 AnyCPU 目标编译应用程序时,它们将在 32 位操作系统上加载为 32 位,在 64 位操作系统上加载为 64 位。您无法从 64 位进程加载 32 位 DLL。

您说过它在编译为 x86 时“有效”。你能做到这一点吗?这让我相信您的搜索路径中的 cryptui.dll 是一个 32 位 DLL。

When applications are compiled with AnyCPU target, they will load as 32-bit on 32 bit OS, and 64-bit on 64 bit OS. You cannot load a 32-bit DLL from a 64-bit process.

You have said that it "works" when compiling to x86. Can you just do this? This leads me to believe that the cryptui.dll in your search path is a 32-bit DLL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文