Get timestamp from Authenticode Signed files in .NET

前端 未结 7 1024
广开言路
广开言路 2020-11-30 04:53

We need to verify that binary files are signed properly with digital signature (Authenticode). This can be achieved with signtool.exe pretty easily. However, we need an auto

7条回答
  •  鱼传尺愫
    2020-11-30 05:25

    I wanted to get the subject off the digital certificate, its an OU type string like

    • CN=Microsoft Corporation, OU=MOPR, O=Microsoft Corporation, L=Redmond, S=Washington, C=US

    I found the X509Certificate to be really slow and load the entire file into memory. I tried to read an 800Mb patch file and my memory increased by 800Mb as it read it, and it took over 30 seconds!!

    I have stood on the sholders of the posters above an managed to tweak the above code to get an X509Certificate2 object hundreds of time faster than using the X509 Object.

    Please read my blog post for more details with images of the performance differences. X509Certificate object c# performance and memory issues alternative – fixed

    Try this:

    public static X509Certificate2 GetDigitalCertificate(string filename)
        {
            X509Certificate2 cert = null;
    
            int encodingType;
            int contentType;
            int formatType;
            IntPtr certStore = IntPtr.Zero;
            IntPtr cryptMsg = IntPtr.Zero;
            IntPtr context = IntPtr.Zero;
    
            if (!WinCrypt.CryptQueryObject(
                WinCrypt.CERT_QUERY_OBJECT_FILE,
                Marshal.StringToHGlobalUni(filename),
                (WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
                | WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED
                | WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED), // <-- These are the attributes that makes it fast!!
                WinCrypt.CERT_QUERY_FORMAT_FLAG_ALL,
                0,
                out encodingType,
                out contentType,
                out formatType,
                ref certStore,
                ref cryptMsg,
                ref context))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
    
            // Get size of the encoded message.
            int cbData = 0;
            if (!WinCrypt.CryptMsgGetParam(
                cryptMsg,
                WinCrypt.CMSG_ENCODED_MESSAGE,
                0,
                IntPtr.Zero,
                ref cbData))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
    
            var vData = new byte[cbData];
    
            // Get the encoded message.
            if (!WinCrypt.CryptMsgGetParam(
                cryptMsg,
                WinCrypt.CMSG_ENCODED_MESSAGE,
                0,
                vData,
                ref cbData))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
    
            var signedCms = new SignedCms();
            signedCms.Decode(vData);
    
            if (signedCms.SignerInfos.Count > 0)
            {
                var signerInfo = signedCms.SignerInfos[0];
    
                if (signerInfo.Certificate != null)
                {
                    cert = signerInfo.Certificate;
                }
            }
    
            return cert;
        }
    

    It seems that if you use the "WinCrypt.CERT_QUERY_CONTENT_FLAG_ALL" on the CryptQueryObject call it suffers from the same memory performance hit as the X509Certificate object, but if you trim it down to just the PKCS7 content types it performs like a dream and seems to give me the info I need.

提交回复
热议问题