API/Library to replace signtool.exe

后端 未结 4 583
旧时难觅i
旧时难觅i 2020-12-30 09:03

The Windows SDK ships with a tool called signtool.exe that lets you sign a file with a certificate. I need to do the same thing but in a background service so I\'m on the lo

相关标签:
4条回答
  • 2020-12-30 09:12

    SignTool is using CAPICOM which is the COM wrapper for the Crypto API. You can use either one. If you're going with CAPICOM, you can check the information here.

    0 讨论(0)
  • 2020-12-30 09:12

    I'm getting the same problem as Sebastien. Looking into the API's, it appears that this is for signing enveloped messages. Authenticode -- the code-signing that signtool does -- is different, which is why the EXE doesn't run after the signing.

    I'm still looking for alternatives.

    0 讨论(0)
  • 2020-12-30 09:33

    You can't just script your way around it? Write a simple batch file that gives it the correct arguments and input? That is atleast what we do when we see this problem on a UNIX server.

    0 讨论(0)
  • 2020-12-30 09:36

    For the google-Travelers arriving here:

    This MSDN forum thread says there is a CryptUIWizDigitalSign API in windows. It also points to a blog article by Alejandro Campos Magencio that shows a sample implementation in VB.NET.

    Since a C# version seems to be missing I converted Alejandro's code to C#. Note that the following code only works with files (yet).

    using System;
    using System.Security.Cryptography.X509Certificates;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    
    namespace ConsoleApp1
    {
        /// <summary>
        /// Provides code signing functionality via Windows COM Cryptui.dll.
        /// </summary>
        class Signer
        {
    
            public const Int32 CRYPTUI_WIZ_NO_UI = 1;
            public const Int32 CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE = 1;
            public const Int32 CRYPTUI_WIZ_DIGITAL_SIGN_CERT = 1;
    
            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;
                public string pwszTimestampURL;
                public Int32 dwAdditionalCertChoice;
                public IntPtr pSignExtInfo;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT
            {
                public Int32 dwSize;
                public Int32 cbBlob;
                public IntPtr pbBlob;
            }
    
            [DllImport("Cryptui.dll", CharSet = CharSet.Unicode, SetLastError = true)]
            public static extern bool CryptUIWizDigitalSign(Int32 dwFlags, IntPtr hwndParent, 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);
    
            /// <summary>
            /// Signs the executable at the given path with the given code signing certificate.
            /// </summary>
            /// <example>
            ///    string certPath = @"C:\certs\CodeSigningTestCert.pfx";
            ///    string exePath = @"C:\temp\ConsoleApp2ToBeSigned.exe";
            ///    string certPwd = "myGreatSecurePassword";
            ///    
            ///    try
            ///    {
            ///        string resultingSignature = Signer.SignExecutable(certPath, exePath, certPwd);
            ///    }
            ///    catch (Win32Exception ex)
            ///    {
            ///        Console.WriteLine(ex.Message + ", Native error code: " + ex.NativeErrorCode.ToString());
            ///    }
            ///    catch (Exception ex)
            ///    {
            ///        // Any unexpected errors?
            ///        Console.WriteLine(ex.Message);
            ///    }
            /// 
            /// </example>
            /// <param name="certPath">The absolute path to the PFX file to be used for signing the exe file.</param>
            /// <param name="exePath">The absolute path to the executable to be signed.</param>
            /// <param name="certPwd">The password for the PFX file.</param>
            public static string SignExecutable(string certPath, string exePath, string certPwd)
            {
                X509Certificate2 cert = default(X509Certificate2);
    
                CRYPTUI_WIZ_DIGITAL_SIGN_INFO digitalSignInfo = default(CRYPTUI_WIZ_DIGITAL_SIGN_INFO);
                CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT signContext = default(CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT);
    
                IntPtr pSignContext = default(IntPtr);
                IntPtr pSigningCertContext = default(IntPtr);
    
                // Get certificate context
                cert = new X509Certificate2(certPath, certPwd);
                pSigningCertContext = cert.Handle;
    
                // Prepare signing info: exe and cert
                digitalSignInfo = new CRYPTUI_WIZ_DIGITAL_SIGN_INFO();
                digitalSignInfo.dwSize = Marshal.SizeOf(digitalSignInfo);
                digitalSignInfo.dwSubjectChoice = CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE;
                digitalSignInfo.pwszFileName = exePath;
                digitalSignInfo.dwSigningCertChoice = CRYPTUI_WIZ_DIGITAL_SIGN_CERT;
                digitalSignInfo.pSigningCertContext = pSigningCertContext;
                digitalSignInfo.pwszTimestampURL = null;
                digitalSignInfo.dwAdditionalCertChoice = 0;
                digitalSignInfo.pSignExtInfo = IntPtr.Zero;
    
                // Sign exe
                if ((!CryptUIWizDigitalSign(CRYPTUI_WIZ_NO_UI, IntPtr.Zero, null, ref digitalSignInfo, ref pSignContext)))
                    throw new Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizDigitalSign");
    
                // Get the blob with the signature
                signContext = (CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT)Marshal.PtrToStructure(pSignContext, typeof(CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT));
                byte[] blob = new byte[signContext.cbBlob + 1];
                Marshal.Copy(signContext.pbBlob, blob, 0, signContext.cbBlob);
    
                // Free blob memory
                if ((!CryptUIWizFreeDigitalSignContext(pSignContext)))
                    throw new Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizFreeDigitalSignContext");
    
                return System.Text.Encoding.Default.GetString(blob);
            }
        }
    }
    

    Hope it helps!

    0 讨论(0)
提交回复
热议问题