четверг, 7 апреля 2011 г.

Проблемы сертификации: Эпизод II - Правила использования

В прошлой заметке я рассказывал о не очевидных причинах возникновения ошибки "Keyset does not exist" и о методах борьбы с ней. А именно: речь шла о правах доступа к файлу приватного ключа сертификата. Продолжая начатую тему странных сообщений CryptoAPI, я хочу рассказать о не менее загадочной ошибке - "Bad key".

Bad key
Текст сообщения об ошибке, возникающей при попытке расшифровать данные, поражает своей лаконичностью - предположить можно всё что угодно. При этом не имеет значения, каким средством дешифрования вы пользовались: нативной функцией CryptDecrypt из библиотеки CryptoAPI, или методом Decrypt класса RSACryptoServiceProvider из пространства имён System.Security.Cryptography. На самом же деле данная ошибка с высокой долей вероятности означает, что используемый сертификат всего-навсего не предназначен для обмена данными.

Эта проблема наиболее характерна для тестовых сертификатов, сгенерированных утилитой makecert.exe, и применяемых отделом контроля качества. Но бывает, что в данную ловушку попадает и клиент. Если приложению требуется сертификат для шифрования / де-шифрования, то достаточно всего лишь предложить ему воспользоваться sign-only сертификатом, чтобы увидеть жалобы CryptoAPI на "плохой ключ". К сожалению, у этой проблемы есть только одно решение: необходимо сгенерировать или купить правильный сертификат.
Каждый сертификат X.509 содержит следующие поля и расширения, описывающие назначение сертификата:
  • Subject's Key Specification - свойство приватного ключа, может принимать значения 1 (AT_KEYEXCHANGE - ключ для шифрования и подписи) или 2 (AT_SIGNATURE - ключ только для подписи);
  • Key Usage - расширение сертификата X.509 v3; значение представляет собой битовую маску, каждый бит которой определяет то или иное назначение; например, бит 2, если установлен, определяет, что сертификат может использоваться в процедуре обмена ключами (Key Exchange).
  • Extended Key Usage - расширение сертификата X.509 v3; представляет собой набор Object Identifier`ов (OID), определяющих дополнительные назначения сертификата; например, добавление OID1.3.6.1.5.5.7.3.2 определяет, что сертификат может использоваться для аутентификации клиентов.
Примечательным является то, что все вышеперечисленные свойства и расширения по сути является независимыми друг от друга. Они могут появляться в сертификате в разных комбинациях и даже противоречить друг другу. К счастью подобные сертификаты - с противоречащими декларациями назначений - являются ошибочными. На сайте Technet`а есть хорошая статья, описывающая в частности, как можно сравнить разные спецификации назначения сертификата на предмет непротиворечивости: http://technet.microsoft.com/en-us/library/dd277392.aspx.

Зачем же нужно такое многообразие деклараций назначений сертификата? Всё очень просто. Как не сложно заметить, каждая последующая декларация расширяет предыдущую. Если Key Specification задаёт только 2 назначения, то Key Usage уже 8, в то время как Extended Key Usage вообще не ограничена сверху. Таким образом, каждое приложение выбирает для проверки то поле, которое наиболее точно соответствует его целям. Если назначение сертификата не соответствует требованиям приложения, оно должно отказаться от его использования и сообщить об ошибке. То есть в общем случае подобная проверка возлагается на само приложение.

К сожалению, в документации отсутствует упоминание того, какие спецификации использования CryptoAPI проверяет автоматически и делает ли она это вообще. Но из этого правила есть, по крайней мере, одно исключение: проверка Key Specification выполняется автоматически. И происходит это вот почему. В отличие от расширений Key Usage и Extended Key Usage, которые являются по сути всего лишь декларациями о намерениях, Key Specification определяет алгоритм, применяемый с ключом сертификата. Поэтому попытка применить для операций шифрования / де-шифрования ключ, предназначенный для формирования цифровой подписи, заканчивается ошибкой Bad key.

Напоследок приведу пример команды, позволяющей сгенерировать тестовый сертификат, который можно применять в операциях шифрования:
makecert -pe -sky Exchange -r -n "CN=<name>" -ss My
Всё дело в дополнительном параметре -sky Exchange, который заставляет утилиту makecert сгенерировать сертификат, пригодный для операций шифрования.

Комментариев нет:

Отправить комментарий