Статус: Новичок
Группы: Участники
Зарегистрирован: 16.07.2019(UTC) Сообщений: 4 
|
Добрый день! Проект на C#. Использую pinvoke. Привожу код, в котором CryptSignHash всегда false. Прошу подсказать в чем проблема. Цитата: // Открываем хранилище сертификатов var hStoreHandle = CryptoAPI.CertOpenStore(CryptoAPI.CERT_STORE_PROV_SYSTEM, 0, (IntPtr)0, CryptoAPI.CERT_SYSTEM_STORE_CURRENT_USER, "MY"); if (hStoreHandle != null) { Console.WriteLine($"Хендл хранилища сертификатов: {hStoreHandle.ToString()}"); } else { var er = CryptoAPI.GetLastError(); Console.WriteLine(er.ToString()); }
//получаем указатель на сертификат var pSignerCert = CryptoAPI.CertFindCertificateInStore(hStoreHandle, CryptoAPI.MY_TYPE, 0, CryptoAPI.CERT_FIND_SUBJECT_STR, null, (IntPtr)0); if (pSignerCert != null) { Console.WriteLine($"Хендл сертификата: {pSignerCert}"); } else { var er = CryptoAPI.GetLastError(); Console.WriteLine(er.ToString()); }
// через функцию CryptAcquireCertificatePrivateKey получаем доступ к CSP IntPtr phCryptProv = (IntPtr)0; Int32 pdwKeySpec = 0; bool pfCallerFreeProv = false; if (CryptoAPI.CryptAcquireCertificatePrivateKey(pSignerCert, 0, IntPtr.Zero, ref phCryptProv, ref pdwKeySpec, ref pfCallerFreeProv)) { Console.WriteLine($"Дескриптор: {phCryptProv.ToString()}"); } else { var er = CryptoAPI.GetLastError(); Console.WriteLine(er.ToString()); } // сообщение string massage = "тут у нас исходный текст подписанного сообщения"; byte[] pbMessage = System.Text.Encoding.UTF8.GetBytes(massage); Int32 cbMessage = pbMessage.Length; // base64 подписанного сообщения string massage_sign = "MIICOQYJKoZIhvcNAQcCoIICKjCCAiYCAQExDDAKBgYqhQMCAgkFADALBgkqhkiG9w0BBwExggIEMIICAAIBATBzMGUxIDAeBgkqhkiG9w0BCQEWEWluZm9AY3J5cHRvcHJvLnJ1MQswCQYDVQQGEwJSVTETMBEGA1UEChMKQ1JZUFRPLVBSTzEfMB0GA1UEAxMWVGVzdCBDZW50ZXIgQ1JZUFRPLVBSTwIKZTIq5AACAAQ+1DAKBgYqhQMCAgkFAKCCASowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTMwNTIxMDY0NTQ4WjAvBgkqhkiG9w0BCQQxIgQgjw/LhkSZj8f2gna5q4fu4mAPjGwX7jUSfjYbO8Sm4Dwwgb4GCyqGSIb3DQEJEAIvMYGuMIGrMIGoMIGlMAgGBiqFAwICCQQgoWW4uwCURIWOSFtKX308YR7jXyGHH/1y2MDECzxn7FIwdzBppGcwZTEgMB4GCSqGSIb3DQEJARYRaW5mb0BjcnlwdG9wcm8ucnUxCzAJBgNVBAYTAlJVMRMwEQYDVQQKEwpDUllQVE8tUFJPMR8wHQYDVQQDExZUZXN0IENlbnRlciBDUllQVE8tUFJPAgplMirkAAIABD7UMAoGBiqFAwICEwUABECTQoUA/SuSEEh7h+KudbAQKKMmrzvXDp62N79u42WcvxYqB272qg5SIz7Y+OZ1mcQSQeDCYX3aAhKJBtrL9qYX"; byte[] pbArray = Convert.FromBase64String(massage_sign); Int32 cbArray = pbArray.Length;
//создаем пустой hash объект IntPtr handle = IntPtr.Zero; if (CryptoAPI.CryptCreateHash(phCryptProv, 32798 /*CALG_GR3411*/, IntPtr.Zero, 0, ref handle)) { Console.WriteLine($"Пустой hash: {handle.ToString()}"); } else { var er = CryptoAPI.GetLastError(); Console.WriteLine(er.ToString()); } // Вычисляем hash для нашего сообщения if (CryptoAPI.CryptHashData(handle, pbMessage, (int)pbMessage.Length, 0)) { int i = 0; foreach (var el in pbMessage) { Console.WriteLine($"Hash c данными: {i} - {el.ToString()}"); i++; } } else { var er = CryptoAPI.GetLastError(); Console.WriteLine(er.ToString()); } // Переменные для указателя и длины подписи uint pdwSigLen = 0; byte[] pbSignature = new byte[pdwSigLen]; if (CryptoAPI.CryptSignHash(handle, CryptoAPI.AT_KEYEXCHANGE, IntPtr.Zero, 0, ref pbSignature, ref pdwSigLen)) { Console.WriteLine($"Длина подписи: {pdwSigLen}"); } else { Console.WriteLine(CryptoAPI.GetLastError().ToString()); }
Уж рядил и так и сяк, а CryptSignHash всегда false. В чем дело?
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,504   Сказал «Спасибо»: 554 раз Поблагодарили: 2250 раз в 1756 постах
|
Здравствуйте.
GetLastError молчит? |
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,504   Сказал «Спасибо»: 554 раз Поблагодарили: 2250 раз в 1756 постах
|
pSignerCert и 32798 /*CALG_GR3411*/
соответствуют действительности или сертификат с ГОСТ-2012?
CryptoAPI.AT_KEYEXCHANGE - а если его не будет? Необходимо либо требовать такое условие работы кода, либо в коде обращаться и к ключу подписи, если ключа обмена нет. |
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 16.07.2019(UTC) Сообщений: 4 
|
По сути молчит. Может я неверно настроил маршаллинг, но GetLastError выдает ахинею типа "0" - вот мое исполнение: [DllImport("kernel32.dll", EntryPoint = "GetLastError")] public static extern uint GetLastError();
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 16.07.2019(UTC) Сообщений: 4 
|
1) Тестовый сертификат: CN=CRYPTO-PRO Test Center 2, O=CRYPTO-PRO LLC, L=Moscow, C=RU, E=support@cryptopro.ru 2) CryptoAPI.CryptSignHash(handle, 0, IntPtr.Zero, 0, ref pbSignature, ref pdwSigLen) - если вместо CryptoAPI.AT_KEYEXCHANGE - 0, или CryptoAPI.AT_SIGNATURE - ничего не меняется: false
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,504   Сказал «Спасибо»: 554 раз Поблагодарили: 2250 раз в 1756 постах
|
Автор: AANNTTOONN  1) Тестовый сертификат: CN=CRYPTO-PRO Test Center 2, O=CRYPTO-PRO LLC, L=Moscow, C=RU, E=support@cryptopro.ru 2) CryptoAPI.CryptSignHash(handle, 0, IntPtr.Zero, 0, ref pbSignature, ref pdwSigLen) - если вместо CryptoAPI.AT_KEYEXCHANGE - 0, или CryptoAPI.AT_SIGNATURE - ничего не меняется: false КриптоПРО CSP\Сервис\Протестировать\По сертификату Алгоритм у сертификата ГОСТ-2001? Ошибок нет? Если всё нормально - смотрим внимательно код и описание функций. |
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,504   Сказал «Спасибо»: 554 раз Поблагодарили: 2250 раз в 1756 постах
|
Автор: AANNTTOONN  1) Тестовый сертификат: CN=CRYPTO-PRO Test Center 2, O=CRYPTO-PRO LLC, L=Moscow, C=RU, E=support@cryptopro.ru Это сертфикат тестового УЦ. Где клиентский сертификат? |
|
|
|
|
Статус: Эксперт
Группы: Участники
Зарегистрирован: 05.03.2015(UTC) Сообщений: 1,602  Откуда: Иркутская область Сказал(а) «Спасибо»: 110 раз Поблагодарили: 395 раз в 366 постах
|
Автор: AANNTTOONN  2) CryptoAPI.CryptSignHash(handle, 0, IntPtr.Zero, 0, ref pbSignature, ref pdwSigLen) - если вместо CryptoAPI.AT_KEYEXCHANGE - 0, или CryptoAPI.AT_SIGNATURE - ничего не меняется: false Прочитайте пожалуйста справку внимательно, в Вашем коде уже получено функцией CryptAcquireCertificatePrivateKey значение pdwKeySpec связанное с ключом выбранного сертификата. Его и нужно передать в CryptSignHash вместо жестко прописанного AT_KEYEXCHANGE или AT_SIGNATURE. Смысл в том, что хотя на практике гост это почти не встречается, но в одном контейнере может быть 2 ключа и соответственно к контейнеру можно привязать 2 сертификата. Если в такой ситуации выбирать dwKeySpec наугад, то неизвестно подпишите ли тем сертификатом, что выбрали из хранилища. Маловероятная ситуация, но лучше сразу прикрыть слабое место программы. Подбирать может потребоваться только если сначала получали имя контейнера для сертификата (тут dwKeySpec насколько помню не возвращается), затем получали контейнер по имени. При переборе желательно сверить открытый ключ из контейнера и из сертификата на соответствие. В Вашем случае (получение контейнера через CryptAcquireCertificatePrivateKey) перебор не нужен, dwKeySpec известно, открытый ключ сверяется внутри функции CryptAcquireCertificatePrivateKey при указании соответствующего флага. Автор: AANNTTOONN  GetLastError выдает ахинею типа "0" По ошибке: для получения длины нужно передать вместо pbSignature пустой указатель IntPtr.Zero (то есть null), иначе функция CryptSignHash будет трактовать длину как уже указанную Вами, проверять указатель на буфер через IsBadWritePtr и споткнется на значении длины 0. Не то чтобы я смотрел код самой функции, но это базовая логика во всех WinApi функциях связанных с получением значений/длины. Передаете вместо буфера null в случае успеха записывается требуемая длина буфер, передаете буфер и длину буфера - записывается использованная длина буфера. Предположительно при этом внутренний вызов IsBadWritePtr с нулевой длиной буфера перезапишет код ошибки нулем. Заметьте: если Вы запросите длину, а потом подпишите, то у пользователя дважды запросит пин-код на контейнер (один раз для запроса длины, второй раз для собственно подписи). Либо ставьте предопределенную для алгоритма длину сразу (без дополнительного запроса длины), 130 байтов достаточно для гост-2001 и гост-2012 256 бит - тогда пользователя не будет дважды спрашивать пин-код. В моей программе используется такое решение, потому что немного странно запрашивать пин-код чтобы узнать длину фиксированную для алгоритмов гост. Отредактировано пользователем 17 июля 2019 г. 8:12:24(UTC)
| Причина: Не указана
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 16.07.2019(UTC) Сообщений: 4 
|
спасибо. решил противоречие перезаказом сертификата и изменением сигнатуры метода.
|
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close