logo
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline ___Алексей_Васильев___  
#1 Оставлено : 10 июля 2019 г. 17:59:44(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

Добрый день. Занимаюсь встраиванием метки времени на C# (ответ на запрос к TSP серверу обрабатываю через Bouncy Castle C# из него получаю токен) в уже существующую подпись (полученную через вызов CryptSignMessage) с использованием CryptoApi на данный момент делаю реализацию под платформу Windows.

Поискав информацию на форумах (новом и старом) понял что алгоритм получения подписи должен иметь следующий вид:
1) формируем запрос к tsp серверу, в качестве данных указываем хэш вычисленный от значения подписи;
2) получаем ответ, извлекаем токен, а именно нас интересует TimeStampToken.GetEncoded() массив байт в закодированном виде

Из полученного массива байт извлекаю информацию о подписанте как говорилось в обсуждении https://www.cryptopro.ru...aspx?g=posts&t=11317

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

Online two_oceans  
#2 Оставлено : 11 июля 2019 г. 5:41:22(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 438
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 26 раз
Поблагодарили: 106 раз в 102 постах
Добрый день. Заранее извинюсь, я на другом языке программирования работаю, поэтому маршаллинг мне кажется подозрительным в целом. Судя по коду ошибки, произошел отказ при обращении к памяти, так что где-то передан неверный указатель. Либо неверная длина из-за которой происходит обращение к невыделенной памяти (например, ставите в блоб длину одной переменной, в указатель другую переменную). Частный случай - отсутствие #0 в конце строки из-за чего также может неверно определиться длина возникнуть обращение к невыделенной памяти (в этом смысле стоит проверить cryptAttribute.pszObjId).

Для ясности можно все потенциальные указатели проверить функциями IsBadReadPtr и IsBadWritePtr, где длина не ясна указать хотя бы 4 (это отсеет неверные указатели и можно будет проверять длины и наличие #0). IsBadReadPtr возвращает TRUE если указатель неверный, FALSE если все в порядке.
Автор: ___Алексей_Васильев___ Перейти к цитате
Код:
                        var encoded_signer_data_ptr = Marshal.AllocHGlobal(pSignerInfoBin.Length);
			Marshal.Copy(encoded_signer_data, 0, encoded_signer_data_ptr, encoded_signer_data.Length);
Вот эти строки мне кажутся немного подозрительными. Маршаллинг похоже не всегда работает правильно. Если уже есть данные, полученные из CryptoAPI, лучше именно их и использовать, чтобы избежать ошибок маршаллинга.
Автор: ___Алексей_Васильев___ Перейти к цитате
Код:
CRYPT_ATTR_BLOB cryptBlob;
В принципе нет необходимости объявлять отдельную переменную, потом ее копировать. Полагаю должно сработать и так (чтобы избежать потенциальных ошибок копирования CRYPT_ATTR_BLOB):
Код:
			cryptAttribute.rgValue.cbData = (uint)encoded_signer_data.Length;
			cryptAttribute.rgValue.pbData = encoded_signer_data_ptr;
Копируя указатели из переменной в переменную не стоит забывать что если где-то освободили память это возможно повлияет на несколько переменных. Вообще тут конечно возможна проблема с длиной: для encoded_signer_data_ptr выделяли насколько я понимаю pSignerInfoBin.Length, а указываете encoded_signer_data.Length. Не проще ли тогда взять указатель на encoded_signer_data и отказаться от encoded_signer_data_ptr?
Автор: ___Алексей_Васильев___ Перейти к цитате
[MarshalAs(UnmanagedType.LPStr)]public string pszObjId;
Немного подозрительная строка в объявлении типа.

Offline ___Алексей_Васильев___  
#3 Оставлено : 11 июля 2019 г. 9:19:22(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

Автор: two_oceans Перейти к цитате
Добрый день. Заранее извинюсь, я на другом языке программирования работаю, поэтому маршаллинг мне кажется подозрительным в целом. Судя по коду ошибки, произошел отказ при обращении к памяти, так что где-то передан неверный указатель. Либо неверная длина из-за которой происходит обращение к невыделенной памяти (например, ставите в блоб длину одной переменной, в указатель другую переменную). Частный случай - отсутствие #0 в конце строки из-за чего также может неверно определиться длина возникнуть обращение к невыделенной памяти (в этом смысле стоит проверить cryptAttribute.pszObjId).

Для ясности можно все потенциальные указатели проверить функциями IsBadReadPtr и IsBadWritePtr, где длина не ясна указать хотя бы 4 (это отсеет неверные указатели и можно будет проверять длины и наличие #0). IsBadReadPtr возвращает TRUE если указатель неверный, FALSE если все в порядке.
Автор: ___Алексей_Васильев___ Перейти к цитате
Код:
                        var encoded_signer_data_ptr = Marshal.AllocHGlobal(pSignerInfoBin.Length);
			Marshal.Copy(encoded_signer_data, 0, encoded_signer_data_ptr, encoded_signer_data.Length);
Вот эти строки мне кажутся немного подозрительными. Маршаллинг похоже не всегда работает правильно. Если уже есть данные, полученные из CryptoAPI, лучше именно их и использовать, чтобы избежать ошибок маршаллинга.
Автор: ___Алексей_Васильев___ Перейти к цитате
Код:
CRYPT_ATTR_BLOB cryptBlob;
В принципе нет необходимости объявлять отдельную переменную, потом ее копировать. Полагаю должно сработать и так (чтобы избежать потенциальных ошибок копирования CRYPT_ATTR_BLOB):
Код:
			cryptAttribute.rgValue.cbData = (uint)encoded_signer_data.Length;
			cryptAttribute.rgValue.pbData = encoded_signer_data_ptr;
Копируя указатели из переменной в переменную не стоит забывать что если где-то освободили память это возможно повлияет на несколько переменных. Вообще тут конечно возможна проблема с длиной: для encoded_signer_data_ptr выделяли насколько я понимаю pSignerInfoBin.Length, а указываете encoded_signer_data.Length. Не проще ли тогда взять указатель на encoded_signer_data и отказаться от encoded_signer_data_ptr?
Автор: ___Алексей_Васильев___ Перейти к цитате
[MarshalAs(UnmanagedType.LPStr)]public string pszObjId;
Немного подозрительная строка в объявлении типа.



Спасибо за ответ. Убрал из кода все что связанно с выделением памяти через Marshal. В параметры функций передаю массивы как есть. Так же убрал атрибут [MarshalAs(UnmanagedType.LPStr)]. Ситуация не изменилась, ошибка та же...Пробовал менять значение pszObjId, указал пустое значение получил ошибку 0x80070057, указал значение "1" получил ошибку 0x80093109 - это чтобы проверить что функция реагирует на изменение этого параметра.

Может ли проблема быть в том что BouncyCastle.TimeStampToken.GetEncoded() - возвращает массив байт который не может переварить CryptoApi, может быть при кодировании структуры полученной из этого массива байт что то идет не так...и далее из-за этого не получается закодировать атрибут...Планирую сейчас разобраться с добавлением какого-нибудь другого неподписанного атрибута, чтобы отладить этот процесс...В остальном вопрос остается открытым, буду признателен за любую помощь
Online two_oceans  
#4 Оставлено : 11 июля 2019 г. 10:11:46(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 438
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 26 раз
Поблагодарили: 106 раз в 102 постах
Автор: ___Алексей_Васильев___ Перейти к цитате
Так же убрал атрибут [MarshalAs(UnmanagedType.LPStr)].
Немного поясню мысль, тут уже надо разбираться с конкретной средой и языком программирования. Смысл моего подозрения был в том, что LPStr это указатель на буфер строки и потому объявлять его строкой нужно только со 100% уверенностью в особенностях компилятора и маршаллинга. Возможно видели что развели на хабре, когда Майкрософт выложили исходники калькулятора из Десятки. На некоторых компилятора Си часть кода была недостижимой потому что условие всегда ложно.
Хотя если реакция есть и стабильно воспроизводится, возможно тут все в порядке (компилятор что-то автоматически исправил).
Цитата:
Может ли проблема быть в том что BouncyCastle.TimeStampToken.GetEncoded() - возвращает массив байт, который не может переварить CryptoApi.
Тут наверно нужен пример массива байт (файлом или шестнадцатиричной записью).

Отредактировано пользователем 11 июля 2019 г. 10:16:31(UTC)  | Причина: Не указана

Offline ___Алексей_Васильев___  
#5 Оставлено : 11 июля 2019 г. 10:34:13(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

timestamp_getencoded.txt (4kb) загружен 7 раз(а).
Автор: two_oceans Перейти к цитате
Автор: ___Алексей_Васильев___ Перейти к цитате
Так же убрал атрибут [MarshalAs(UnmanagedType.LPStr)].
Немного поясню мысль, тут уже надо разбираться с конкретной средой и языком программирования. Смысл моего подозрения был в том, что LPStr это указатель на буфер строки и потому объявлять его строкой нужно только со 100% уверенностью в особенностях компилятора и маршаллинга. Возможно видели что развели на хабре, когда Майкрософт выложили исходники калькулятора из Десятки. На некоторых компилятора Си часть кода была недостижимой потому что условие всегда ложно.
Хотя если реакция есть и стабильно воспроизводится, возможно тут все в порядке (компилятор что-то автоматически исправил).
Цитата:
Может ли проблема быть в том что BouncyCastle.TimeStampToken.GetEncoded() - возвращает массив байт, который не может переварить CryptoApi.
Тут наверно нужен пример массива байт (файлом или шестнадцатиричной записью).


Online two_oceans  
#6 Оставлено : 11 июля 2019 г. 13:12:39(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 438
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 26 раз
Поблагодарили: 106 раз в 102 постах
Интересно, Asn1 Editor дает ошибку "Длина данных слишком большая".
Offline ___Алексей_Васильев___  
#7 Оставлено : 11 июля 2019 г. 13:29:59(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

Автор: two_oceans Перейти к цитате
Интересно, Asn1 Editor дает ошибку "Длина данных слишком большая".


Распарсил байты токена в asn1 time_stamp_token_asn1.txt (23kb) загружен 3 раз(а).
Offline ___Алексей_Васильев___  
#8 Оставлено : 11 июля 2019 г. 15:12:57(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

Еще хотелось бы уточнить, для добавления штампа в подпись нам действительно нужно из токена получить информацию о структуре CMSG_SIGNER_INFO? и пытаться на основе нее (после кодирования CryptEncodeObject) формировать CRYPT_ATTRIBUTE (с pszObjId = "1.2.840.113549.1.9.16.1.4"), единственная информация которую мне удалось найти по данной теме это ссылка из 1 поста. Может кто то объяснить почему так нужно/не нужно делать или хотя бы подсказать где об этом можно почитать
Online two_oceans  
#9 Оставлено : 12 июля 2019 г. 7:13:29(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 438
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 26 раз
Поблагодарили: 106 раз в 102 постах
Детально в стандарт я не вчитывался, но идея думаю правдоподобная. Почитать наверно RFC 5126 (cades), RFC 3161 (Time-Stamp Protocol) и https://www.cryptopro.ru/products/pki/tsp/tasks для общей картины.
Offline ___Алексей_Васильев___  
#10 Оставлено : 12 июля 2019 г. 11:24:26(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

Разобрался с проблемой. Штамп добавляется для этого структуры описал следующим образом:

[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_ATTRIBUTE
{
public string pszObjId;
public uint cValue;
public IntPtr rgValue;
}

[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_ATTR_BLOB
{
public uint cbData;
public IntPtr pbData;
}

Перед кодированием атрибута все оборачиваю в IntPtr

CRYPT_ATTR_BLOB blb = new CRYPT_ATTR_BLOB();
blb.cbData = encoded_signer_len;
blb.pbData = hSignerInfoEncoded;

var blobLocalAllocHandle = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CRYPT_ATTR_BLOB)));
Marshal.StructureToPtr(blb, blobLocalAllocHandle, false);

var cryptAttribute = new CRYPT_ATTRIBUTE();
cryptAttribute.pszObjId = "1.2.840.113549.1.9.16.1.4";
cryptAttribute.cValue = 1;
cryptAttribute.rgValue = blobLocalAllocHandle;

IntPtr hAttr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CRYPT_ATTRIBUTE)));
Marshal.StructureToPtr(cryptAttribute, hAttr, false);

Соответственно параметр функции на вход принимает IntPtr(hAttr)
Offline ___Алексей_Васильев___  
#11 Оставлено : 12 июля 2019 г. 11:45:31(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

Полученная подпись со штампом проходит проверку через КриптоАрм. Но вот значение штампа почему то выводится в виде массива байт. Об этой проблеме как раз говорилось в https://www.cryptopro.ru...spx?g=posts&t=11317.

Отображается в виде 30 82 05 56 02 01 01 30 82 01 58 30 82 01 48 31 18 30 16 06 05 2a 85 03 64 01 12 0d 31 30 33 37 37 30 30 30 38 35 34 34 34 31 1a 30 18 06 08 2a 85 03 03 81 03 01 01 12 0c 30 30 37 37 31 37 31 30 37 39 39 31 31 39 30 37 06 03 55 04 09 1e 30 04 43 04 3b 00 2e 00 20 04 21 04 43 04 49 04 51 04 32 04 41 04 3a 04 38 04 39 00 20 04 32 04 30 04 3b 00 2c 00 20 04 34 00 2e 00 20 00 31 00 38 31 21 30 1f 06 03 55 04 08 1e 18 00 37 00 37 00 20 04 33 00 2e 00 20 04 1c 04 3e 04 41 04 3a 04 32 04 30 31 15 30 13 06 03 55 04 07 1e 0c 04 1c 04 3e 04 41 04 3a 04 32 04 30 31 20 30 1e 06 09 2a 86 48 86 f7 0d 01 09 01 16 11 69 6e 66 6f 40 63 72 79 70 74 6f 70 72 6f 2e 72 75 31 0b 30 09 06 03 55 04 06 13 02 52 55 31 29 30 27 06 03 55 04 0a 1e 20 04 1e 04 1e 04 1e 00 20 00 22 04 1a 04 20 04 18 04 1f 04 22 04 1e 00 2d 04 1f 04 20 04 1e 00 22 31 41 ....

Подскажите из-за чего это может быть? Особенности получения токена через BouncyCastle?
Ожидал увидеть примерно следующий вид:

Штамп времени на подпись
Точность -1
Идентификатор политики 1.2.3.4.42
Статус Запрос успешно обработан
Время 23.04.2019 15:19:00 UTC+06
Серийный номер 133258AEE60000000000128FCA
Сертификат службы штампов времени
Информация о сертификате
Параметры сертификата:

Версия: 3

Серийный номер: 01FDA2D300E5A9758543FED52AB5AF4834

Издатель: Тестовый подчиненный УЦ ООО "КРИПТО-ПРО" ГОСТ 2012 (УЦ 2.0), info@cryptopro.ru, 1037700085444, 007717107991, RU, 77 Москва, Москва, ул. Сущёвский вал д. 18, ООО "КРИПТО-ПРО"

Действителен с: 30.01.2019 18:40:33 UTC+06
Действителен до: 30.01.2029 18:01:44 UTC+06

Владелец: Тестовый оператор TSP, 007717107991, 1037700085444, ООО "КРИПТО-ПРО", ул. Сущевский Вал, д. 18, Москва, 77 Москва, RU


Online two_oceans  
#12 Оставлено : 12 июля 2019 г. 12:51:03(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 438
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 26 раз
Поблагодарили: 106 раз в 102 постах
То есть фундаментально изменили по сравнению с первым сообщением копирование на Marshal.StructureToPtr?

Автор: ___Алексей_Васильев___ Перейти к цитате
Полученная подпись со штампом проходит проверку через КриптоАрм. Но вот значение штампа почему то выводится в виде массива байт. Об этой проблеме как раз говорилось в https://www.cryptopro.ru...aspx?g=posts&t=11317
Подскажите из-за чего это может быть? Особенности получения токена через BouncyCastle?
Полагаю, скопировался какой-то "вредный совет" из той темы, оид вероятно не тот или тип атрибута или надо немного обертку блоба срезать. Желательно выяснить вообще этот атрибут сейчас влияет на проверку подписи или нет? Например, если перевести время на тот момент когда сертификат закончится пройдет ли подпись проверку. Если нет, то атрибут ни на что по факту не влияет и он хоть и закодирован успешно, но неверный по смыслу.

По оиду версию проверить проще всего: судя по прочитанным сегодня вполглаза по диагонали стандартам, оид с окончанием .1.4 попадался в протоколе TSP, а c окончанием .2.14 фигурируровал в стандарте cades. Полагаю логичнее использовать значение что в cades. Соответственно, может быть не срабатывает автоматический разбор значения атрибута из-за другого оида. Если не поможет, то надо вчитываться в стандарт или сравнивать с правильно разбираемым файлом.
Offline ___Алексей_Васильев___  
#13 Оставлено : 15 июля 2019 г. 11:42:32(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

Автор: two_oceans Перейти к цитате
То есть фундаментально изменили по сравнению с первым сообщением копирование на Marshal.StructureToPtr?

Автор: ___Алексей_Васильев___ Перейти к цитате
Полученная подпись со штампом проходит проверку через КриптоАрм. Но вот значение штампа почему то выводится в виде массива байт. Об этой проблеме как раз говорилось в https://www.cryptopro.ru...aspx?g=posts&t=11317
Подскажите из-за чего это может быть? Особенности получения токена через BouncyCastle?
Полагаю, скопировался какой-то "вредный совет" из той темы, оид вероятно не тот или тип атрибута или надо немного обертку блоба срезать. Желательно выяснить вообще этот атрибут сейчас влияет на проверку подписи или нет? Например, если перевести время на тот момент когда сертификат закончится пройдет ли подпись проверку. Если нет, то атрибут ни на что по факту не влияет и он хоть и закодирован успешно, но неверный по смыслу.

По оиду версию проверить проще всего: судя по прочитанным сегодня вполглаза по диагонали стандартам, оид с окончанием .1.4 попадался в протоколе TSP, а c окончанием .2.14 фигурируровал в стандарте cades. Полагаю логичнее использовать значение что в cades. Соответственно, может быть не срабатывает автоматический разбор значения атрибута из-за другого оида. Если не поможет, то надо вчитываться в стандарт или сравнивать с правильно разбираемым файлом.


Да, действительно был указан неверный OID атрибута, из-за чего подпись воспринималась как Cades-Bes, а не Cades-T, которая мне нужна. Заменил Oid на 1.2.840.113549.1.9.16.2.14 (id-aa-signatureTimeStampToken) и заношу в атрибут значение токена как есть (вместо кодирования структуры SIGNER_INFO). При проверке на ресурсе https://www.justsign.me/verifyqca/Verify/ верно определяется тип подписи Cades-T и даже отображается значение "Время подписи полученное из штампа времени", но в результате получаю ошибку: "Не удалось проверить подпись CAdES-T. Ошибка: [Элемент не найден]. Код: [0x80070490].В сообщении не найден действительный штамп времени на подпись." Нашел похожу проблему https://www.cryptopro.ru...spx?g=posts&t=14482, но из ответа непонятно куда и какой сертификат нужно добавить и какой адрес нужно изменить на общедоступный?
Online two_oceans  
#14 Оставлено : 16 июля 2019 г. 5:50:07(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 438
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 26 раз
Поблагодарили: 106 раз в 102 постах
Цитата:
Полученная подпись со штампом проходит проверку через КриптоАрм. Но вот значение штампа почему то выводится в виде массива байт.
Автор: ___Алексей_Васильев___ Перейти к цитате
Да, действительно был указан неверный OID атрибута, из-за чего подпись воспринималась как Cades-Bes, а не Cades-T, которая мне нужна. Заменил Oid на 1.2.840.113549.1.9.16.2.14 (id-aa-signatureTimeStampToken) и заношу в атрибут значение токена как есть (вместо кодирования структуры SIGNER_INFO).
Что-то обстоятельства меняются быстро: и средство проверки изменилось и оид и кодирование. Если по порядку: 1) в КриптоАрм теперь проверка проходит и правильно выводится значение? Если проверка не проходит, нужно более подробно смотреть на каком шаге "спотыкается". 2) Что мотивировало отказаться от кодирования? 3) С какой-то верной подписью сравнивали?

Цитата:
При проверке на ресурсе https://www.justsign.me/verifyqca/Verify/ верно определяется тип подписи Cades-T и даже отображается значение "Время подписи полученное из штампа времени", но в результате получаю ошибку: "Не удалось проверить подпись CAdES-T. Ошибка: [Элемент не найден]. Код: [0x80070490].В сообщении не найден действительный штамп времени на подпись.
Это сообщение можно толковать по-разному: 1) либо вообще никакой штамп времени не найден; 2) либо штамп времени найден, но штамп недействительный или не удалось проверить его действительность.
Тема на которую приведена ссылка адресует второй случай. Речь, как я понимаю, идет о сертификате тестового УЦ, который выпустил сертификат подписавшего и сертификат сервера доверенного времени. Сертификат УЦ не был добавлен в Доверенные сертификаты на justsign и из-за этого не проходила проверка. Другими словами самостоятельно Вы тут ничего не добавите.

У Вас же скорее всего сейчас немного другой случай, то есть штамп присутствует, но без кодирования в нем полагаю нет достаточной информации о подписавшем сервере времени. Соответственно, при проверке неизвестно как проверить действительность самого штампа времени.
Offline ___Алексей_Васильев___  
#15 Оставлено : 16 июля 2019 г. 12:28:37(UTC)
___Алексей_Васильев___

Статус: Новичок

Группы: Участники
Зарегистрирован: 06.01.2019(UTC)
Сообщений: 9
Российская Федерация

Автор: two_oceans Перейти к цитате
Цитата:
Полученная подпись со штампом проходит проверку через КриптоАрм. Но вот значение штампа почему то выводится в виде массива байт.
Автор: ___Алексей_Васильев___ Перейти к цитате
Да, действительно был указан неверный OID атрибута, из-за чего подпись воспринималась как Cades-Bes, а не Cades-T, которая мне нужна. Заменил Oid на 1.2.840.113549.1.9.16.2.14 (id-aa-signatureTimeStampToken) и заношу в атрибут значение токена как есть (вместо кодирования структуры SIGNER_INFO).
Что-то обстоятельства меняются быстро: и средство проверки изменилось и оид и кодирование. Если по порядку: 1) в КриптоАрм теперь проверка проходит и правильно выводится значение? Если проверка не проходит, нужно более подробно смотреть на каком шаге "спотыкается". 2) Что мотивировало отказаться от кодирования? 3) С какой-то верной подписью сравнивали?

Цитата:
При проверке на ресурсе https://www.justsign.me/verifyqca/Verify/ верно определяется тип подписи Cades-T и даже отображается значение "Время подписи полученное из штампа времени", но в результате получаю ошибку: "Не удалось проверить подпись CAdES-T. Ошибка: [Элемент не найден]. Код: [0x80070490].В сообщении не найден действительный штамп времени на подпись.
Это сообщение можно толковать по-разному: 1) либо вообще никакой штамп времени не найден; 2) либо штамп времени найден, но штамп недействительный или не удалось проверить его действительность.
Тема на которую приведена ссылка адресует второй случай. Речь, как я понимаю, идет о сертификате тестового УЦ, который выпустил сертификат подписавшего и сертификат сервера доверенного времени. Сертификат УЦ не был добавлен в Доверенные сертификаты на justsign и из-за этого не проходила проверка. Другими словами самостоятельно Вы тут ничего не добавите.

У Вас же скорее всего сейчас немного другой случай, то есть штамп присутствует, но без кодирования в нем полагаю нет достаточной информации о подписавшем сервере времени. Соответственно, при проверке неизвестно как проверить действительность самого штампа времени.


В качестве средств для проверки использую КриптоАрм и сервис https://www.justsign.me/verifyqca/Verify/. В случае КриптоАрма - проверка выполняется с результатом "Один или несколько штампов времени недействительны.". При этом сама подпись действительна, сертификат действителен, но на вкладке "Штамп времени" указано: "Штамп времени недействителен (или отсутствует лицензия)". При этом заполнены свойства штампа, а именно серийный номер, время в штампе, точность штампа и идентификатор политики (1.2.643.2.2.38.4). Так же указано что сертификат действителен.

Касательно проверки через сервис https://www.justsign.me/verifyqca/Verify/. В разделе "Дополнительная информация о подписи", определяется формат подписи CADES-T, выводится время подписи полученное из штампа и время подписи. Так же выводится информация о сертификате. Однако результат проверки: "Подпись недействительна", Дополнительная информация: "Не удалось проверить подпись CAdES-T. Ошибка: [Элемент не найден]. Код: [0x80070490].В сообщении не найден действительный штамп времени на подпись.".

От кодирования я не отказывался, токен полученный через GetEncoded уже имеет закодированный вид. Oid изменил т.к в спецификации CAdES-T (ETSI TS 101 733 «CMS Advanced Electronic Signatures (CadES)» сказано что для создания подписи CAdES-T необходимо добавить атрибут с oid 1.2.840.113549.1.9.16.2.14 (https://www.etsi.org/deliver/etsi_ts/101700_101799/101733/02.02.01_60/ts_101733v020201p.pdf 38 стр), соответственно в него требуется записывать полученный токен времени.

Так же проверил ASN.1 структуру подписей, в двух из которых штамп времени определяется как действительный, сравнил с той что формирую я. Выяснил что одна из подписей с "валидным" штампом имеет формат CAdES-C т.к в ней присутствуют элементы со следующими oid-ами (1.2.840.113549.1.9.16.2.(21-24)), кроме наличия данных элементов разницы в секции описания штампа времени не обнаружил. Вторая подпись с "валидным" штампом, которую я взял из https://www.cryptopro.ru...aspx?g=posts&t=14482 имеет структуру штампа аналогичную моей + содержит два атрибута с oid-ами организации...

RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.