API/Library to replace signtool.exe

99封情书 提交于 2019-11-29 08:02:47

问题


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 lookout for a library (preferably managed code, but COM will do) to do the same thing. Any ideas?

Found the answer. Here's how to use an X.509 certificate to sign a file in .NET:

CmsSigner signer = new CmsSigner();
signer.Certificate = new X509Certificate2(certificate);

SignedCms content = new SignedCms(new ContentInfo(File.ReadAllBytes(fileToSign)));
content.ComputeSignature(signer, true);
byte[] signedFile = content.Encode();

string signedFileName = fileToSign + ".signed";
File.WriteAllBytes(signedFileName, signedFile);

Console.WriteLine("Signed file: " + signedFileName);

Here, certificate is the path to the .pfx file containing the certificate and fileToSign is the file to sign.


回答1:


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.




回答2:


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!




回答3:


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.




回答4:


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.



来源:https://stackoverflow.com/questions/510773/api-library-to-replace-signtool-exe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!