使用PInvoke的CryptoAPI的SignerTimeStampEx2

rus*_*gil 3 c# pinvoke timestamp sha256 cryptoapi

我正在尝试使用C#代码中的CryptoAPI将SHA256时间戳添加到已签名的程序集中.这是我正在使用的代码:

Signer.TimestampSignedAssembly("MyAssembly.exe", "http://tsa.starfieldtech.com");
Run Code Online (Sandbox Code Playgroud)

签名者类:

public static class Signer
{
    [StructLayoutAttribute(LayoutKind.Sequential)]
    struct SIGNER_SUBJECT_INFO
    {
        public uint cbSize;
        public IntPtr pdwIndex;
        public uint dwSubjectChoice;
        public SubjectChoiceUnion Union1;
        [StructLayoutAttribute(LayoutKind.Explicit)]
        internal struct SubjectChoiceUnion
        {
            [FieldOffsetAttribute(0)]
            public IntPtr pSignerFileInfo;
            [FieldOffsetAttribute(0)]
            public IntPtr pSignerBlobInfo;
        }
    }

    [StructLayoutAttribute(LayoutKind.Sequential)]
    struct SIGNER_FILE_INFO
    {
        public uint cbSize;
        public IntPtr pwszFileName;
        public IntPtr hFile;
    }

    [DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int SignerTimeStampEx2(
        uint dwFlags,               // DWORD
        IntPtr pSubjectInfo,        // SIGNER_SUBJECT_INFO
        string pwszHttpTimeStamp,   // LPCWSTR
        uint dwAlgId,               // ALG_ID
        IntPtr psRequest,           // PCRYPT_ATTRIBUTES
        IntPtr pSipData,            // LPVOID 
        out IntPtr ppSignerContext  // SIGNER_CONTEXT
        );

    public static void TimestampSignedAssembly(string appPath, string tsaServer)
    {
        if (tsaServer == null) throw new ArgumentNullException("tsaServer");

        var pSubjectInfo = IntPtr.Zero;            
        try
        {                
            pSubjectInfo = CreateSignerSubjectInfo(appPath);
            TimestampSignedAssembly(pSubjectInfo, tsaServer);
        }
        finally
        {                
            if (pSubjectInfo != IntPtr.Zero)
            {
                Marshal.DestroyStructure(pSubjectInfo, typeof(SIGNER_SUBJECT_INFO));
            }                
        }
    }

    private static IntPtr CreateSignerSubjectInfo(string pathToAssembly)
    {
        var info = new SIGNER_SUBJECT_INFO
        {
            cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)),
            pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)))
        };
        var index = 0;
        Marshal.StructureToPtr(index, info.pdwIndex, false);

        info.dwSubjectChoice = 0x1; //SIGNER_SUBJECT_FILE
        var assemblyFilePtr = Marshal.StringToHGlobalUni(pathToAssembly);

        var fileInfo = new SIGNER_FILE_INFO
        {
            cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_FILE_INFO)),
            pwszFileName = assemblyFilePtr,
            hFile = IntPtr.Zero
        };

        info.Union1 = new SIGNER_SUBJECT_INFO.SubjectChoiceUnion
        {
            pSignerFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_FILE_INFO)))
        };

        Marshal.StructureToPtr(fileInfo, info.Union1.pSignerFileInfo, false);

        IntPtr pSubjectInfo = Marshal.AllocHGlobal(Marshal.SizeOf(info));
        Marshal.StructureToPtr(info, pSubjectInfo, false);

        return pSubjectInfo;
    }

    /* 
        Here CryptoAPI function SignerTimeStampEx2 called.
    */
    private static void TimestampSignedAssembly(IntPtr pSubjectInfo, string tsaServer)
    {            
        IntPtr context;
        var hResult = SignerTimeStampEx2(
            0x1,            // I have not found anywhere what value should have this parameter!
            pSubjectInfo,   
            tsaServer,      
            0x0000800c,     // 256 bit SHA hashing algorithm. This value taken form here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
            IntPtr.Zero,    
            IntPtr.Zero,
            out context
            );

        if (hResult != 0)
        {
            throw new Exception(string.Format("Error occured when adding timestamp - Error code: 0x{0:X}", hResult));
        }
    }
}   
Run Code Online (Sandbox Code Playgroud)

尽管我向SignerTimeStampEx2函数传递了一个参数(dwAlgId),表明有必要添加SHA256时间戳(0x0000800c),但始终会生成SHA1时间戳.

有谁遇到过这个问题?我做错了什么?我应该为dwFlagsdwAlgId参数设置什么值?

提前致谢!

Jan*_*rts 6

dwFlags需要是SIGNER_TIMESTAMP_RFC3161(2).你会得到一个访问冲突的原因是SignerTimeStampEx2()被证明不正确.它期望算法作为PCSTR而不是DWORD.如果你传递0x800C,它会尝试取消引用作为指针,导致AV.因此,使用PCSTR pszTimeStampAlgorithmOid替换函数声明中的ALG_ID dwAlgId.将szOID_NIST_sha256传递给它,它应定义为"2.16.840.1.101.3.4.2.1".

SignerTimeStampEx3()也被错误地记录错误.pszTimeStampAlgorithmOid应声明为PCSTR而不是PCWSTR.

根据我的经验,如果在SIGNER_FILE_INFO结构中同时指定文件名和打开的Win32文件句柄,则代码签名和时间戳更可靠.

您是否真正获得SHA-256时间戳还取决于您正在使用的时间戳服务. http://tsa.starfieldtech.com,http : //timestamp.globalsign.com/http://timestamp.comodoca.com/rfc3161发布SHA-256时间戳.即使请求SHA-256时间戳,其他服务也可能会发出SHA-1时间戳.