【问题标题】:CryptoAPI's SignerTimeStampEx2 using PInvokeCryptoAPI 的 SignerTimeStampEx2 使用 PInvoke
【发布时间】:2013-10-18 02:07:08
【问题描述】:

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

Signer.TimestampSignedAssembly("MyAssembly.exe", "http://tsa.starfieldtech.com");

签名者类:

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

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

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

提前致谢!

【问题讨论】:

  • +1。我认为您应该使用 SIGNER_TIMESTAMP_RFC3161 作为第一个标志。现在...我也不知道在哪里可以找到 SIGNER_TIMESTAMP_RFC3161 和 SIGNER_TIMESTAMP_AUTHENTICODE 值...在反汇编 mssign32.dll 时,我认为“1”表示 SIGNER_TIMESTAMP_AUTHENTICODE(因为 SignerTimeStamp 以 1 作为第一个参数值调用 SignerTimeStampEx3)。所以你应该尝试 0、2 或 3 作为标志值。
  • 感谢您的回答。我尝试将 0、2 和 3 作为标志值传递并得到以下结果:0 和 3 - 发生 0x80070057 错误(一个或多个参数无效),2 - crypt32.dll 中的 APPCRASH(错误代码 - c0000005,访问冲突?)
  • 所以它的进步:-) 你也可以修改 SIGNER_FILE_INFO 中的 pwszFileName。只需使用一个字符串并将 CharSet = CharSet.Unicode 添加到结构定义中。
  • 你让它工作了吗?我从来没有。

标签: c# timestamp pinvoke sha256 cryptoapi


【解决方案1】:

dwFlags 需要为 SIGNER_TIMESTAMP_RFC3161 (2)。您遇到访问冲突的原因是 SignerTimeStampEx2() 错误地是 documented。它期望算法为 PCSTR 而不是 DWORD。如果您传递 0x800C,它将尝试将其作为指针取消引用,从而导致 AV。因此,将函数声明中的 ALG_ID dwAlgId 替换为 PCSTR pszTimeStampAlgorithmOid。将 szOID_NIST_sha256 传递给它,它应该定义为“2.16.840.1.101.3.4.2.1”。

SignerTimeStampEx3() 也是错误的 documented。 pszTimeStampAlgorithmOid 应声明为 PCSTR 而不是 PCWSTR。

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

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

【讨论】:

  • 我刚刚遇到了类似的问题,实际上 SignerTimeStampEx2 可以 用于签署文件,但是 SignerTimeStampEx2 的 API 文档是错误的,而不是将 ALG_ID 作为参数,它还需要一个带有时间戳算法 oid 的 PCSTR,正如你提到的,对于 sha256,它是“2.16.840 ....”。
  • 问题是我要签名的不是文件,而是blob,而且总是失败……应该传递哪个guid?
  • 你有没有找到一种方法来为 blob 加时间戳?
【解决方案2】:

我终于让它工作了。下面是 Timestamper 类的完整代码:

public static class Timestamper
{
    [StructLayout(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
        IntPtr pszTimeStampAlgorithmOid, // PCSTR
        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");

        IntPtr 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)
    {
        SIGNER_SUBJECT_INFO info = new SIGNER_SUBJECT_INFO
        {
            cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)),
            pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)))
        };

        int index = 0;
        Marshal.StructureToPtr(index, info.pdwIndex, false);

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

        SIGNER_FILE_INFO 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;
        int hResult = SignerTimeStampEx2(
            0x2, // SIGNER_TIMESTAMP_RFC3161
            pSubjectInfo,
            tsaServer,
            Marshal.StringToHGlobalAnsi("2.16.840.1.101.3.4.2.1"), // szOID_NIST_sha256 constant, SHA256 hashing algorithm.
            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));
        }
    }
}

使用示例:

Timestamper.TimestampSignedAssembly("Assembly.exe", "http://timestamp.comodoca.com/?td=sha256");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多