我正在尝试使用 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 时间戳。
有人遇到过这个问题吗?我做错了什么?我应该为 dwFlags 和 dwAlgId 参数设置什么值?
提前致谢!
最佳答案
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.com , http://timestamp.globalsign.com/和 http://timestamp.comodoca.com/rfc3161发出 SHA-256 时间戳。即使在请求 SHA-256 时间戳时,其他服务也可能会发出 SHA-1 时间戳。
关于c# - 使用 PInvoke 的 CryptoAPI 的 SignerTimeStampEx2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19293651/