Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

5 Страницы<12345>
Опции
К последнему сообщению К первому непрочитанному
Offline two_oceans  
#21 Оставлено : 19 апреля 2020 г. 16:44:40(UTC)
two_oceans

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

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

Сказал(а) «Спасибо»: 110 раз
Поблагодарили: 394 раз в 366 постах
Цитата:
var pCertContext = CryptoApi.CertCreateCertificateContext(X509_ASN_ENCODING, certResult, certSize);
Как я понимаю, pCertContext тут тоже самое что значение certificate.Handle в
Цитата:
if (CryptoApi.CertSetCertificateContextProperty(certificate.Handle, 2 /* CERT_KEY_PROV_INFO_PROP_ID */, 0, pvData)) /
то есть как проставить ссылку Вы уже знаете: укажите pCertContext вместо certificate.Handle и ссылка проставится в pCertContext. В хранилище ставить (Store.Open и т.д.) не так чтобы остро необходимо (но дальше остается вопрос куда пристроить pCertContext со ссылкой чтобы его принимал CmsSigner, если не в хранилище). В .net я тоже не особенно шарю, но есть подозрение, что CmsSigner берет именно из хранилища, чего бы ему не передали.

Наверно можно обойти если найти точно такое же свойство как pCertContext в классе CmsSigner и исправить (точнее сделать копию и изменить) сам класс CmsSigner с возможностью передать туда готовое значение pCertContext со ссылкой без последующего поиска в хранилище. Это может по цепочке потребовать правку еще кучи классов.

Поэтому как вариант - работать с CryptSignMessage. Сертификат там передается дважды - один раз для подписания, второй для включения в подпись. Массивы сертификатов (и других параметров) можно трактовать как единичный параметр если поставить счетчик элементов соответствующего массива в 1 и передавать один pCertContext (само значение pCertContext уже указатель, передавать указатель на переменную pCertContext).

Отредактировано пользователем 19 апреля 2020 г. 16:56:47(UTC)  | Причина: Не указана

Offline LONG11  
#22 Оставлено : 19 апреля 2020 г. 20:42:09(UTC)
LONG11

Статус: Активный участник

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

Сказал(а) «Спасибо»: 24 раз
Автор: Андрей * Перейти к цитате
Автор: two_oceans Перейти к цитате
Выше же вроде все описано
https://www.cryptopro.ru...&m=114343#post114343

Поясняю, в сообщении выше описан цикл получения данных ContainerName -> hProv -> hPubKey -> pCertContext


Так это другая ветка проблемы, её решили.
А результат не совместим с cmsSigner - в этом проблема.


Андрей, я сформулировал вопрос, если можете, подскажите, пожалуйста, - вообще возможен ли такой сценарий работы:

Прописать объекту certificate, который получен из контейнера токена:
Код:
var pCertContext = CryptoApi.CertCreateCertificateContext(X509_ASN_ENCODING, certResult, certSize);
var certificate = new X509Certificate2(certResult, new System.Security.SecureString(), X509KeyStorageFlags.PersistKeySet);

Ссылку на закрытый ключ?

Я сейчас почитал про установку ссылки на закрытый ключ и прописал вот так (дополнительно к структуре CRYPT_KEY_PROV_INFO):

Код:
 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        internal struct CERT_KEY_CONTEXT
        {
            internal uint cbSize;
            internal IntPtr hCryptProv;
            internal uint dwKeySpec;
        }

CryptoApi.CERT_KEY_CONTEXT keyContext =
                         new CryptoApi.CERT_KEY_CONTEXT();
                    
                    keyContext.cbSize = (uint)Marshal.SizeOf(typeof(CryptoApi.CERT_KEY_CONTEXT));
                    keyContext.hCryptProv = hProv; // тут ссылка на дескриптор провайдера
                    keyContext.dwKeySpec = 2;
                    pvData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CryptoApi.CERT_KEY_CONTEXT)));
                    Marshal.StructureToPtr(keyContext, pvData, false);
                    var s = CryptoApi.CertSetCertificateContextProperty(certificate.Handle, 5, 0, pvData); //CERT_KEY_CONTEXT_PROP_ID=5


Если в принципе невозможно прописать такую ссылку, я больше в этом направлении думать не буду. Если же это возможно, то хотелось бы подсказки как этого добиться.

На форуме прямого ответа не нашел, может плохо искал...

Т.е. после выполнения "привязок" все равно ошибка: Ключ не существует.

в CryptoPro.Sharpei.CPUtils.GetKeyPairHelper(CPCspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandleCP& safeProvHandle, SafeKeyHandleCP& safeKeyHandle)
в CryptoPro.Sharpei.Gost3410_2012_256CryptoServiceProvider.GetKeyPair()
в CryptoPro.Sharpei.Gost3410_2012_256CryptoServiceProvider..ctor(CspParameters parameters)
в CryptoPro.Sharpei.NetDetours.CPX509Certificate2.get_PrivateKey()

Получается это криптопровайдер Крипто-Про не дает совершить привязку?

Но почему тогда при установке этой привязки не вызывает проблем последующий экспорт сертификата в Личное хранилище?
Получается экспортировать сертификат можно с привязкой, и последующее создание объекта х509 со ссылкой на экспортированный сертификат не вызывает ошибок, т.е.
х509.privatekey = true
А продолжать первоначальную работу с объектом х509, когда осуществил привязку - невозможно.
Почему?
Возможно это политика работы с Провайдером КриптоПро и необходимость приобретения Крипто Про.NET (как предположение)?

Отредактировано пользователем 19 апреля 2020 г. 21:22:32(UTC)  | Причина: Не указана

Offline LONG11  
#23 Оставлено : 21 апреля 2020 г. 10:09:51(UTC)
LONG11

Статус: Активный участник

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

Сказал(а) «Спасибо»: 24 раз
С прошлым вопросом разобрался, спасибо.

Подписал одинаковый массив байт двумя способами:

1) p/invoke
CryptSignMessage(ref SignPara, true, 1, rgpbToBeSigned, rgcbToBeSigned, pbSignedMessageBlob, ref signSize);

2) .NET
signedCms.ComputeSignature(cmsSigner, false);
pk = signedCms.Encode();

Далее сделал Convert.ToBase64String для pk и для pbSignedMessageBlob.

Вижу разные значения. Очередной дилетантский вопрос:
Почему значения разные? Ведь и та и другая функции хешируют массив байт, подписывают его и кодируют.
Online Андрей *  
#24 Оставлено : 21 апреля 2020 г. 11:05:48(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 12,709
Мужчина
Российская Федерация

Сказал «Спасибо»: 500 раз
Поблагодарили: 2051 раз в 1591 постах
Автор: LONG11 Перейти к цитате
С прошлым вопросом разобрался, спасибо.

Подписал одинаковый массив байт двумя способами:

1) p/invoke
CryptSignMessage(ref SignPara, true, 1, rgpbToBeSigned, rgcbToBeSigned, pbSignedMessageBlob, ref signSize);

2) .NET
signedCms.ComputeSignature(cmsSigner, false);
pk = signedCms.Encode();

Далее сделал Convert.ToBase64String для pk и для pbSignedMessageBlob.

Вижу разные значения. Очередной дилетантский вопрос:
Почему значения разные? Ведь и та и другая функции хешируют массив байт, подписывают его и кодируют.

можно прямо так и спросить яндекс: почему ...
раз в полгода возникает вопрос на форуме...


далее попадаем в faq\support\форумные темы.

делюсь ссылкой на Knowledgebase из support.
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Андрей * за этот пост.
LONG11 оставлено 21.04.2020(UTC)
Offline two_oceans  
#25 Оставлено : 21 апреля 2020 г. 11:51:26(UTC)
two_oceans

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

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

Сказал(а) «Спасибо»: 110 раз
Поблагодарили: 394 раз в 366 постах
Мне вопрос задается кажется гораздо чаще. Ну, в базе знаний только про RAW подпись (что половина "подписи" гост - это случайное значение, а другая половина "проверочное" значение, которое должно получиться если выполнить с хэшем данных, тем случайным значением и открытым ключом из сертификата заданный алгоритм) и не отражено еще много факторов для Cades / Pades:
1) может быть включена цепочка сертификатов, а может быть не включена, может быть неполная цепочка. Регулируется параметрами.
2) могут добавляться еще атрибуты (многие атрибуты - необязательные в самом "легком" подформате, но становятся обязательными когда более сложная версия используется), может подписываться не сам массив данных (назову файл для простоты), а атрибуты (один из подписанных атрибутов - хэш файла).
3) результат уже может быть в base64, а потом его "еще разок" преобразовали. Это касается в основном подписания в плагине, но надо обращать внимание получили бинарные данные или уже в base64.

А иногда еще и про то что в одной записи начинается с MII..., а в другой MIA...

Отредактировано пользователем 21 апреля 2020 г. 11:59:19(UTC)  | Причина: Не указана

Online Андрей *  
#26 Оставлено : 21 апреля 2020 г. 12:15:42(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 12,709
Мужчина
Российская Федерация

Сказал «Спасибо»: 500 раз
Поблагодарили: 2051 раз в 1591 постах
Автор: two_oceans Перейти к цитате
Мне вопрос задается кажется гораздо чаще. Ну, в базе знаний только про RAW подпись (что половина "подписи" гост - это случайное значение, а другая половина "проверочное" значение, которое должно получиться если выполнить с хэшем данных, тем случайным значением и открытым ключом из сертификата заданный алгоритм) и не отражено еще много факторов для Cades / Pades:
1) может быть включена цепочка сертификатов, а может быть не включена, может быть неполная цепочка. Регулируется параметрами.
2) могут добавляться еще атрибуты (многие атрибуты - необязательные в самом "легком" подформате, но становятся обязательными когда более сложная версия используется), может подписываться не сам массив данных (назову файл для простоты), а атрибуты (один из подписанных атрибутов - хэш файла).
3) результат уже может быть в base64, а потом его "еще разок" преобразовали. Это касается в основном подписания в плагине, но надо обращать внимание получили бинарные данные или уже в base64.

А иногда еще и про то что в одной записи начинается с MII..., а в другой MIA...


Для меня "различная" - это означает именно подпись - её значение в hex, а не в том, что вокруг неё есть своя PKI-экосистема.
и в KB об этом явно написано, да..
>>При этом на выходе каждый раз получается разный результат
т.е. если в цикле крутить CryptSignMessage - то всегда разная
аналогично, если пытаться сверять с низкоуровневым API.
Техническую поддержку оказываем тут
Наша база знаний
Offline LONG11  
#27 Оставлено : 21 апреля 2020 г. 15:21:34(UTC)
LONG11

Статус: Активный участник

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

Сказал(а) «Спасибо»: 24 раз
Наверное, пора сдаваться. И не пытаться скрестить ежа с со слоном.

В общем споткнулся на том, что скрещиваю нескрещиваемое... (с встраиванием в PDF):

Код:
X509CertificateParser parser = new X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain =
new Org.BouncyCastle.X509.X509Certificate[] { parser.ReadCertificate(x509.RawData) };

sap.Certificate = chain[0];
sap.SignDate = DateTime.Now;
sap.Reason = "Reason!";
sap.Location = "Location!";

// Выбираем подходящий тип фильтра
PdfName filterName = new PdfName("CryptoPro PDF");
// Создаем подпись
PdfSignature dic = new PdfSignature(filterName, PdfName.ADBE_PKCS7_DETACHED);
dic.Date = new PdfDate(DateTime.Now);
dic.Name = "Sign-test";
dic.Reason = "Reason!";
dic.Location = "Location!";
sap.CryptoDictionary = dic;
//какая-то магия, но видимо тут и определяется массив для подписи
int intCSize = 8000; //4000
Dictionary<PdfName, int> hashtable = new Dictionary<PdfName, int>();
hashtable[PdfName.CONTENTS] = intCSize * 2 + 2;

sap.PreClose(hashtable);
Stream s = sap.GetRangeStream();

MemoryStream ms = new MemoryStream();
int read = 0;
byte[] buff = new byte[8192];
while ((read = s.Read(buff, 0, 8192)) > 0)
    {
       ms.Write(buff, 0, read);
    }


Далее следует все как в примере у нормальных людей:

Код:
//ContentInfo  - тип PKCS #7 (как я прочел)
ContentInfo contentInfo = new ContentInfo(ms.ToArray());
SignedCms signedCms = new SignedCms(contentInfo, true);
CmsSigner cmsSigner = new CmsSigner(x509);
byte[] pk = null;


signedCms.ComputeSignature(cmsSigner, false); //если не ввести container password - исключение
pk = signedCms.Encode();
var www = Convert.ToBase64String(pbSignedMessageBlob); //это просто глазами смотрел
byte[] outc = new byte[intCSize];
PdfDictionary dic2 = new PdfDictionary();
Array.Copy(pk, 0, outc, 0, pk.Length);

dic2.Put(PdfName.CONTENTS, new PdfString(outc).SetHexWriting(true));
sap.Close(dic2);
fs.Close();
st.Close();
reader.Close();


И все работает, если средствами NET подписание.
Связки CryptSignMessage и работы по встраиванию а PDF с iTextSharp ни в одном Гугле не нашел.

Решил поступить на "авось", посмотрел, что массив данных получается выше и подсовывается:
Код:
ContentInfo contentInfo = new ContentInfo(ms.ToArray());

и далее используются методы .NET влез со своим CryptSignMessage

byte[] data = ms.ToArray();

вместо: ContentInfo contentInfo = new ContentInfo(ms.ToArray());
и дальше пошел подписывать byte[] data

Код:

IntPtr[] rgpbToBeSigned = new IntPtr[1];
int[] rgcbToBeSigned = new int[1];
CRYPT_SIGN_MESSAGE_PARA SignPara = new CRYPT_SIGN_MESSAGE_PARA();

IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(data[0]) * data.Length);
Marshal.Copy(data, 0, buffer, data.Length);

rgpbToBeSigned[0] = buffer;
rgcbToBeSigned[0] = 1; // 1 или 0 вроде ни на что не влияла

SignPara.cbSize = Marshal.SizeOf(SignPara);
SignPara.dwMsgEncodingType = MY_ENCODING_TYPE;
SignPara.pSigningCert = pCertContext;//signingCert.Handle;
SignPara.HashAlgorithm.pszObjId = "1.2.643.7.1.1.2.2"; 
SignPara.HashAlgorithm.Parameters.cbData = 0;
SignPara.HashAlgorithm.Parameters.pbData = null;
SignPara.pvHashAuxInfo = IntPtr.Zero;


//добавляю только свой сертификат без цепочки
SignPara.cMsgCert = 1;
GCHandle GC = GCHandle.Alloc(pCertContext, GCHandleType.Pinned);
SignPara.rgpMsgCert = GC.AddrOfPinnedObject();
GC.Free();

SignPara.cMsgCrl = 0;
SignPara.cAuthAttr = 0;
SignPara.dwInnerContentType = 0;
SignPara.cUnauthAttr = 0;
SignPara.dwFlags = 0;
SignPara.pvHashAuxInfo = IntPtr.Zero;
SignPara.rgAuthAttr = IntPtr.Zero;

Int32 cbSignedMessageBlob = 0;
Byte[] pbSignedMessageBlob = null;

int signSize = 0;
//определяю размер
CryptSignMessage(ref SignPara, true, 1, rgpbToBeSigned, rgcbToBeSigned, null, ref signSize);
pbSignedMessageBlob = new Byte[signSize];
//получаю pbSignedMessageBlob
CryptSignMessage(ref SignPara, true, 1, rgpbToBeSigned, rgcbToBeSigned, pbSignedMessageBlob, ref signSize);


Далее, получив pbSignedMessageBlob и считая его подписанным и закодированным хешем я дальше засовываю его в PDF:

pk = pbSignedMessageBlob;

Код:
byte[] outc = new byte[intCSize];
PdfDictionary dic2 = new PdfDictionary();
Array.Copy(pk, 0, outc, 0, pk.Length);

dic2.Put(PdfName.CONTENTS, new PdfString(outc).SetHexWriting(true));
sap.Close(dic2);
fs.Close();
st.Close();
reader.Close(); 


На выходе имею файл PDF. В нем имеется сертификат. Но все остальное пишет:
Подпись не определена
Подпись недействительна
Подпись сделана в формате CADES BES
Сертификат ненадежный
Документ был изменен или поврежден с момента подписания

Когда же подписываю signedCms.ComputeSignature все проходит на отлично.

Подскажите, в какую сторону нужно смотреть дальше.

Отредактировано пользователем 21 апреля 2020 г. 15:23:33(UTC)  | Причина: Не указана

Online Андрей *  
#28 Оставлено : 21 апреля 2020 г. 15:24:00(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 12,709
Мужчина
Российская Федерация

Сказал «Спасибо»: 500 раз
Поблагодарили: 2051 раз в 1591 постах
сравнить ASN.1 от CryptSignMsg и от .Net SignedCMS.

Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Андрей * за этот пост.
LONG11 оставлено 21.04.2020(UTC)
Online Андрей *  
#29 Оставлено : 21 апреля 2020 г. 15:31:27(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 12,709
Мужчина
Российская Федерация

Сказал «Спасибо»: 500 раз
Поблагодарили: 2051 раз в 1591 постах
ms - сохранить в файл
+ подписи, получаемые от CryptSignMsg и от SignedCMS
прислать в ЛС

или самостоятельно проверить, совпадают ли хеши в asn.1,
например, через https://lapo.it/asn1js/
искать: 1.2.840.113549.1.9.4 messageDigest


Snimok ehkrana ot 2020-04-21 16-30-56.png (50kb) загружен 9 раз(а).
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Андрей * за этот пост.
LONG11 оставлено 21.04.2020(UTC)
Online Андрей *  
#30 Оставлено : 21 апреля 2020 г. 16:06:58(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 12,709
Мужчина
Российская Федерация

Сказал «Спасибо»: 500 раз
Поблагодарили: 2051 раз в 1591 постах
Один и тот же файл подписывается?
Пришлите этот файл в ЛС.
Хеши разные.
Слева - это через SignedCMS, справа - от CryptSignMsg,

+ не включен в CMS сертификат подписанта у CryptSignMsg (есть только информация о сертификате: Тестовый подчиненный УЦ ООО "КРИПТО-ПРО" ГОСТ 2012 (УЦ 2.0))

Snimok ehkrana ot 2020-04-21 17-03-44.png (42kb) загружен 10 раз(а).
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Андрей * за этот пост.
LONG11 оставлено 21.04.2020(UTC)
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
5 Страницы<12345>
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.