Добрый день. Занимаюсь встраиванием метки времени на C# (ответ на запрос к TSP серверу обрабатываю через Bouncy Castle C# из него получаю токен) в уже существующую подпись (полученную через вызов CryptSignMessage) с использованием CryptoApi на данный момент делаю реализацию под платформу Windows.
Поискав информацию на форумах (новом и старом) понял что алгоритм получения подписи должен иметь следующий вид:
1) формируем запрос к tsp серверу, в качестве данных указываем хэш вычисленный от значения подписи;
2) получаем ответ, извлекаем токен, а именно нас интересует TimeStampToken.GetEncoded() массив байт в закодированном виде
Из полученного массива байт извлекаю информацию о подписанте как говорилось в обсуждении
https://www.cryptopro.ru...aspx?g=posts&t=11317var cryptMsgTs = CApiExtWin.CryptMsgOpenToDecode(
PKCS_7_OR_X509_ASN_ENCODING,
0,
0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero
);
if (!CApiExtWin.CryptMsgUpdate(cryptMsgTs, timestamp, (uint)timestamp.Length, true))
throw new Exception("CryptMsgUpdate");
uint signer_info_len = 0;
if (!CApiExtWin.CryptMsgGetParam(cryptMsgTs, CMSG_SIGNER_INFO_PARAM, 0, null, ref signer_info_len))
{
var CryptMsgGetParamError = Marshal.GetHRForLastWin32Error();
throw new Exception($"CryptMsgGetParam error: {CryptMsgGetParamError}");
}
var pSignerInfoBin = new byte[signer_info_len];
if (!CApiExtWin.CryptMsgGetParam(cryptMsgTs, CMSG_SIGNER_INFO_PARAM, 0, pSignerInfoBin, ref signer_info_len))
{
var CryptMsgGetParamError = Marshal.GetHRForLastWin32Error();
throw new Exception($"CryptMsgGetParam error: {CryptMsgGetParamError}");
}
var pSignerInfoPtr = Marshal.AllocHGlobal(pSignerInfoBin.Length);
Marshal.Copy(pSignerInfoBin, 0, pSignerInfoPtr, pSignerInfoBin.Length);
CApiExtWin.CryptMsgClose(cryptMsgTs);
uint encoded_signer_len = 0;
if (!CApiExtWin.CryptEncodeObject(PKCS_7_OR_X509_ASN_ENCODING, new IntPtr(PKCS7_SIGNER_INFO), pSignerInfoPtr, null, ref encoded_signer_len))
{
var CryptMsgGetParamError = Marshal.GetHRForLastWin32Error();
throw new Exception($"CryptMsgGetParam error: {CryptMsgGetParamError}");
}
// Данные атрибута подписи
var encoded_signer_data = new byte[encoded_signer_len];
if (!CApiExtWin.CryptEncodeObject(PKCS_7_OR_X509_ASN_ENCODING, new IntPtr(PKCS7_SIGNER_INFO), pSignerInfoPtr, encoded_signer_data, ref encoded_signer_len))
{
var CryptMsgGetParamError = Marshal.GetHRForLastWin32Error();
throw new Exception($"CryptMsgGetParam error: {CryptMsgGetParamError}");
}
На этом этапе все отрабатывает корректно. Далее я формирую значение атрибута:
var encoded_signer_data_ptr = Marshal.AllocHGlobal(pSignerInfoBin.Length);
Marshal.Copy(encoded_signer_data, 0, encoded_signer_data_ptr, encoded_signer_data.Length);
// Открываем закодированное сообщение(подпись)
var cryptMsg = CApiExtWin.CryptMsgOpenToDecode(
PKCS_7_OR_X509_ASN_ENCODING,
0,
0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero
);
if (cryptMsg == IntPtr.Zero)
throw new Exception("Failed to open messsage to decode");
if(!CApiExtWin.CryptMsgUpdate(cryptMsg, sign, (uint)sign.Length, true))
throw new Exception("Failed to add signature block to message");
CRYPT_ATTR_BLOB cryptBlob;
cryptBlob.cbData = (uint)encoded_signer_data.Length; //размер закодированной информации о подписанте;
cryptBlob.pbData = encoded_signer_data_ptr; //закодированная информация о подписанте;
CRYPT_ATTRIBUTE cryptAttribute = new CRYPT_ATTRIBUTE();
cryptAttribute.pszObjId = "1.2.840.113549.1.9.16.1.4"; /*"1.2.840.113549.1.9.16.2.14"*/
cryptAttribute.cValue = 1;
cryptAttribute.rgValue = cryptBlob;
Далее пытаюсь закодировать данный атрибут
uint encoded_len = 0;
if (!CApiExtWin.CryptEncodeObject(PKCS_7_OR_X509_ASN_ENCODING, new IntPtr(PKCS_ATTRIBUTE), cryptAttribute, null, ref encoded_len))
throw new Exception($"Sizing of CryptEncodeObject error. {Marshal.GetHRForLastWin32Error()}");
Тут возникает ошибка. Marshal.GetHRForLastWin32Error() - возвращает HRESULT: 0xC0000005.
Подскажите пожалуйста в чем может быть проблема, или я что то делаю не так?
Описание структур:
[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_ATTRIBUTE
{
[MarshalAs(UnmanagedType.LPStr)]
public string pszObjId;
public uint cValue;
public CRYPT_ATTR_BLOB rgValue;
}
[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_ATTR_BLOB
{
public uint cbData;
public IntPtr pbData;
}