Форум КриптоПро
»
Средства криптографической защиты информации
»
Встраивание
»
Как определить идентификатор алгоритма подписи (оид и параметры), используемого для создания ЭЦП функцией CryptSignHash?
Статус: Участник
Группы: Участники
Зарегистрирован: 29.12.2007(UTC) Сообщений: 22  Откуда: Екатеринбург
|
Для того, чтобы сформировать PKCS10-запрос на сертификат, необходимо заполнить ASN1-структуру Код:CertificationRequest ::= SEQUENCE {
certificationRequestInfo CertificationRequestInfo,
signatureAlgorithm AlgorithmIdentifier,
signature BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
Затруднение вызывает заполнение поля signatureAlgorithm. Понятно, что идентификатор алгоритма подписи для заданного криптопровайдера однозначно выводится из пары (<идентификатор алгоритма открытого ключа>, <идентификатор алгоритма хеширования>). <Идентификатор алгоритма открытого ключа> указывается при создании ключевой пары функцией CryptGenKey() и может быть в дальнейшем восстановлен при помощи функции CryptExportPublicKeyInfo(), а <идентификатор алгоритма хеширования> указывается при создании хеша функцией CryptCreateHash(). Таким образом, в момент генерации ЭЦП эти идентификаторы мне известны и доступны. Для каждой конкретной пары идентификаторов открытого ключа и алгоритма хеширования идентификатор соответствующего алгоритма подписи можно определить, порывшись в различных RFC. Например, для КриптоПро CSP паре (1.2.643.2.2.19 (GOST R 34.10-2001), 1.2.643.2.2.9 (GOST R 34.11-94)) соответствует алгоритм подписи 1.2.643.2.2.3 (GOST R 34.11 / 34.10-2001). Но вот как решить эту задачу в общем виде при помощи универсального кода, обращающегося к CryptoApi, для заранее неизвестных криптопровайдеров? P.S.: По ряду причин при формировании запроса на сертификат мне хотелось бы избежать использования более "высокоуровневых" CryptoApi-функций типа CryptSignCertificate(), которым идентификатор алгоритма подписи передается явно. Кроме того, я все равно должен как-то узнать, какой идентификатор в эту функцию можно передавать для данного криптопровайдера... |
С уважением, Андрей Костоусов СКБ Контур |
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 25.12.2007(UTC) Сообщений: 1,733  Откуда: КРИПТО-ПРО Поблагодарили: 177 раз в 168 постах
|
Надо смотреть, какие алгоритмы поддерживает выбранный криптопровайдер и уже из них выбирать - так например реализована генерация запросов в веб-интерфейсе MS СА. |
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 29.12.2007(UTC) Сообщений: 22  Откуда: Екатеринбург
|
Kirill Sobolev написал:Надо смотреть, какие алгоритмы поддерживает выбранный криптопровайдер и уже из них выбирать - так например реализована генерация запросов в веб-интерфейсе MS СА. Ну, это не метод... Ведь подпись-то функцией CryptSignHash() создается без явного указания идентификатора алгоритма подписи. Сигнатура этой функции просто не предусматривает передачу в нее этой информации. Вместо этого она сама как-то определяет алгоритм, который надо использовать. Для этого в ее распоряжении есть хэндл хеша, созданного при помощи функции CryptCreateHash(), в которую передается идентификатор алгоритма хеширования и хендл крипто-контекста ключевого контейнера, созданного и наполненного ключами при помощи функций CryptAcquireContext() и CryptGenKey(). Короче говоря, нигде в этой вполне штатной цепочке вызовов CryptoApi-функций, приводящей к созданию ЭЦП, идентификатор используемого алгоритма подписи явно не фигурирует. Кстати, COM-объект XEnroll, который, насколько я знаю, используется в веб-интерфейсе MS СА успешно справляется с решеним данной задачи. Для того, чтобы с его помощью создать запрос на сертификат, ему достаточно указать тип и имя криптопровайдера (которые нужны функции CryptAcquireContext()) и идентификатор алгоритма хеширования (который нужен функции CryptCreateHash()): Код://set the CSP
xenroll_.ProviderName = opts.CspName;
xenroll_.ProviderType = opts.CspType;
//set the hash algorithm
xenroll_.HashAlgID = opts.HashAlgorithmId;
У XEnroll'а есть еще куча свойств, которые позволяют задать различные флаги, влияющие на свойства создаваемого ключевого контейнера и ключей в нем, но прямого отношения к рассматриваемому вопросу они не имеют. В результате вызова метода xenroll_.createRequest(XECR_PKCS10_V2_0, ...) создается корректно заполненная ASN1-структура CertificationRequest, в частности, содержащая информацию об алгоритме подписи. При этом XEnroll в процессе создания ключей и запроса на сертификат у пользователя не спрашивает какой алгоритм подписи ему следует использовать. |
С уважением, Андрей Костоусов СКБ Контур |
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 29.12.2007(UTC) Сообщений: 22  Откуда: Екатеринбург
|
Мне кажется, я нашел "правильный" CryptoApi-способ вычисления объектного идентификатора алгоритма подписи по имеющимся идентификаторам алгоритмов хеширования и открытого ключа. Он заключается в вызове функции CryptFindOIDInfo(): Код:ALG_ID pair[2];
pair[0] = hashAlgId;
pair[1] = publicKeyAlgId;
PCCRYPT_OID_INFO pSgnAlgOidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_SIGN_KEY, &pair, CRYPT_SIGN_ALG_OID_GROUP_ID);
//в результате pSgnAlgOidInfo->pszOID содержит интересующий нас оид алгоритма подписи
Тесты показали, что для ГОСТовских алгоритмов при использовании криптопровайдера КриптоПро CSP, а также на обычных RSAшных алгоритмах, встроенных в винду, метод выдает правильный идентификатор алгоритма подписи. Однако данный метод не дает ответа на вопрос, откуда взять параметры алгоритма подписи, которые нужно поместить в поле CertificationRequest.signatureAlgorithm.parameters запроса на сертификат. Правда, насколько я понял, для ГОСТ-алгоритма 1.2.643.2.2.3 (ГОСТ Р 34.11/34.10-2001) и для RSA-алгоритма 1.2.840.113549.1.1.5 (sha1RSA) и вообще для большинства распространенных алгоритмов подписи параметры не указываются, но все-таки... Будут какие-нибудь дополнительные соображения на эту тему? |
С уважением, Андрей Костоусов СКБ Контур |
|
|
|
Статус: Сотрудник
Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC) Сообщений: 6,405  Откуда: КРИПТО-ПРО Сказал «Спасибо»: 37 раз Поблагодарили: 720 раз в 624 постах
|
Мыслите в правильную сторону |
|
|
|
|
Статус: Сотрудник
Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC) Сообщений: 6,405  Откуда: КРИПТО-ПРО Сказал «Спасибо»: 37 раз Поблагодарили: 720 раз в 624 постах
|
Если бы MS так делал везде... |
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 25.12.2007(UTC) Сообщений: 1,733  Откуда: КРИПТО-ПРО Поблагодарили: 177 раз в 168 постах
|
Цитата:Мне кажется, я нашел "правильный" CryptoApi-способ вычисления объектного идентификатора алгоритма подписи по имеющимся идентификаторам алгоритмов хеширования и открытого ключа. Он заключается в вызове функции CryptFindOIDInfo(): Он безусловно правильный, но алгоритмы хеширования и ОК все равно придется определять перебором из доступных для выбранного провайдера. |
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 28.01.2008(UTC) Сообщений: 40  Откуда: Москва Поблагодарили: 3 раз в 2 постах
|
AndrewKostousov написал:По ряду причин при формировании запроса на сертификат мне хотелось бы избежать использования более "высокоуровневых" CryptoApi-функций типа CryptSignCertificate(), На мой взгляд, это неверное решение, т.к. Вы будете дублировать код выбора необходимых OID функций типа PFN_*, а так же сам этот код. Изложите эти причины, быть может, есть и не такой, "сложный" путь их удовлетворения. AndrewKostousov написал:Однако данный метод не дает ответа на вопрос, откуда взять параметры алгоритма подписи, которые нужно поместить в поле CertificationRequest.signatureAlgorithm.parameters запроса на сертификат. Правда, насколько я понял, для ГОСТ-алгоритма 1.2.643.2.2.3 (ГОСТ Р 34.11/34.10-2001) и для RSA-алгоритма 1.2.840.113549.1.1.5 (sha1RSA) и вообще для большинства распространенных алгоритмов подписи параметры не указываются, но все-таки...
Будут какие-нибудь дополнительные соображения на эту тему? Алгоритм и параметры ЭЦП - однозначно определяются именем контейнера и спецификацией закрытого ключа AT_* (дескриптором закрытого ключа). Эти параметры извлекают с помощью CryptGetKeyParam(). Алгоритм (CALG_*) общим для всех образом, а параметры специфичным для провайдера/алгоритма образом, смотрите нашу документацию (CSP_3_*.chm). Для преобразования наших CAPI значений в ASN.1 DER, также смотрите нашу документацию < CPCMS - RFC 4490>, < CPPK - RFC 4491>. Алгоритм и параметры хэш-функции - однозначно определяются дескриптором хэш-функции. Эти параметры извлекают с помощью CryptGetHashParam(). Всё аналогично, смотрите нашу документацию. Остаётся вопрос, как создать хэш-функцию с алгоритмом , которая будет совместима с данным закрытым ключом по операции ЭЦП. По-моему, это можно сделать только перебором всех пар `pair[2]'. Тем не менее, к сожалению, возможна неоднозначность, которая потребует какого-то разрешения, например, выбирать самую длинную. Для упорядочивания произвола в выборе параметров хэш-функции, можно, создавать её с параметрами по умолчанию в рамках HCRYPTPROV контейнера целевого закрытого ключа. Отредактировано пользователем 8 мая 2008 г. 8:33:47(UTC)
| Причина: Не указана |
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 29.12.2007(UTC) Сообщений: 22  Откуда: Екатеринбург
|
Serge3leo написал:На мой взгляд, это неверное решение, т.к. Вы будете дублировать код выбора необходимых OID функций типа PFN_*, а так же сам этот код. Да, мое решение оказалось неверным - в некоторых случаях оно вообще выдавало неправильный идентификатор. В итоге у меня сложилось впечатление, что поставленную в начале топика задачу невозможно решить без использования провайдерно-зависимого кода (по крайней мере, это не легко). В результате, я упростил себе задачу и стал плясать от известных (на стадии разработки) криптопровайдеров и конкретных криптографических алгоритмов, которые нужно поддерживать. Для них все необходимые идентификаторы, параметры и способы их кодирования были заранее собраны и зафиксированы в коде - в конце концов, таких специфических деталей не так уж и много, а излишние обобщения тоже до добра не доводят :-) Что касается Serge3leo написал:AndrewKostousov написал:По ряду причин при формировании запроса на сертификат мне хотелось бы избежать использования более "высокоуровневых" CryptoApi-функций типа CryptSignCertificate(), Изложите эти причины, быть может, есть и не такой, "сложный" путь их удовлетворения. то я имел в виду следующее: поскольку у меня в проекте задача кодирования/декодирования различных ASN.1-структур в DER уже вполне успешно решена при помощи библиотеки BouncyCastle, мне хотелось по-максимуму избежать нудного заполнения CryptoApi-структур наподобие CERT_REQUEST_INFO, которые передаются в "высокоуровневые" функции типа CryptSignAndEncodeCertificate(). Справедливости ради нужно отметить, что конкретно упомянутая мной функция CryptSignCertificate() принимает уже закодированный в DER массив байтов, на что я не сразу обратил внимание. Но от этого она не становится намного более предпочтительной по сравнению с совсем базовой функцией CryptSignHash(). Она лишь скрывает вызовы функций CryptCreateHash(), CryptSignHash() и CryptHashData(), котрые совсем несложно реализовать и самостоятельно, но зато уже не позволяет подписывать произвольные данные, а только корректные ASN.1-объекты в DER-кодировке. В любом случае всем спасибо за потраченное на мой вопрос время! |
С уважением, Андрей Костоусов СКБ Контур |
|
|
|
Форум КриптоПро
»
Средства криптографической защиты информации
»
Встраивание
»
Как определить идентификатор алгоритма подписи (оид и параметры), используемого для создания ЭЦП функцией CryptSignHash?
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close