У меня есть реализация, использующая C ++ CRYPT32.DLL для извлечения объекта SignedCms из dll сборки c # со знаком.
Срок действия сертификата, используемого для подписания библиотеки DLL, истек, но внутри имеется действующая цепочка сертификатов. Важно то, что сертификат состоит из трех сертификатов, которые я все хочу извлечь.
private static readonly int CERT_QUERY_OBJECT_FILE = 0x00000001;
private static readonly int CERT_QUERY_CONTENT_FLAG_ALL = 0x00003ffe;
private static readonly int CERT_QUERY_FORMAT_FLAG_ALL = 0x0000000e;
private static readonly int CMSG_ENCODED_MESSAGE = 29;
[DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool CryptQueryObject(
int dwObjectType,
IntPtr pvObject,
int dwExpectedContentTypeFlags,
int dwExpectedFormatTypeFlags,
int dwFlags,
IntPtr pdwMsgAndCertEncodingType,
IntPtr pdwContentType,
IntPtr pdwFormatType,
IntPtr phCertStore,
IntPtr phMsg,
IntPtr ppvContext
);
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool CryptMsgGetParam(
IntPtr hCryptMsg, int dwParamType, int dwIndex, IntPtr pvData, ref int pcbData );
public static SignedCms GetSignedCmsFromFile(string fileName)
{
var pvObject = Marshal.StringToHGlobalUni(fileName);
var phMessage = Marshal.AllocHGlobal(IntPtr.Size);
var pvData = IntPtr.Zero;
try
{
SignedCms signedCms = null;
var success = CryptQueryObject(
CERT_QUERY_OBJECT_FILE,
pvObject,
CERT_QUERY_CONTENT_FLAG_ALL,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
phMessage,
IntPtr.Zero);
if (success)
{
var hMessage = Marshal.ReadIntPtr(phMessage);
var cbData = 0;
success = CryptMsgGetParam(
hMessage,
CMSG_ENCODED_MESSAGE,
0,
IntPtr.Zero,
ref cbData);
if (success)
{
var data = new byte[cbData];
pvData = Marshal.AllocHGlobal(sizeof(byte) * data.Length);
success = CryptMsgGetParam(
hMessage,
CMSG_ENCODED_MESSAGE,
0,
pvData,
ref cbData);
if (success)
{
Marshal.Copy(pvData, data, 0, cbData);
signedCms = new SignedCms();
try
{
signedCms.Decode(data);
File.WriteAllBytes(fileName + ".export", data);
}
catch (CryptographicException)
{
signedCms = null;
}
}
}
}
return signedCms;
}
finally
{
if (pvObject != IntPtr.Zero)
Marshal.FreeHGlobal(pvObject);
if (phMessage != IntPtr.Zero)
Marshal.FreeHGlobal(phMessage);
if (pvData != IntPtr.Zero)
Marshal.FreeHGlobal(pvData);
}
}
Функция работает очень хорошо, но так как функция crypt32.dll устарела, я ищу чистую реализацию C #, которая делает то же самое и предоставляет объект SignedCms.
Самое близкое, что я смог найти, - сертификат X509.
X509Certificate2 cert = new X509Certificate2(fileName)
Функция CryptQueryObject
Решение
Благодаря посту ниже я смог реализовать чистый метод C # для извлечения SignedCms.
Единственное, что не подходит идеально, это то, что startindex выключен на 8 байтов, а размер на 10 байтов меньше.
public static SignedCms GetSignedCmsFromFile(string fileName)
{
var result = new SignedCms();
uint startIndex = 0;
uint size = 0;
var reader = new PeHeaderReader(fileName);
if (reader.Is32BitHeader)
{
startIndex = reader.OptionalHeader32.CertificateTable.VirtualAddress;
size = reader.OptionalHeader32.CertificateTable.Size;
}
else
{
startIndex = reader.OptionalHeader64.CertificateTable.VirtualAddress;
size = reader.OptionalHeader64.CertificateTable.Size;
}
//var data = File.ReadAllBytes(fileName).Skip((int)startIndex).Take((int)size).ToArray();
//Somehow the start index and size are not fitting perfectly and I have to adapt them
var data = File.ReadAllBytes(fileName).Skip((int)startIndex + 8).Take((int)size - 10).ToArray();
result.Decode(data);
return result;
}