Каково обоснование для всех различных X509KeyStorageFlags? - PullRequest
0 голосов
/ 11 октября 2018

Сегодня коллега обнаружил еще одну ошибку, связанную с этим!В прошлом я обнаружил, что эти флаги действительно разочаровывают, потому что если вы ошибаетесь, когда создаете экземпляры объектов X509Certificate2, или экспортируете их, или сохраняете их в магазине X509, вы можете столкнуться с ситуациями со всевозможными странными ошибками, такими как:

  • неожиданно не может сказать NETSH.exe или ASP.net использовать определенный сертификат SSL [по его отпечатку пальца], даже если у вас есть этот сертификат в вашем машинном магазине
  • , неожиданно вы можетеэкспортируйте данные сертификата, но они будут экспортированы без использования закрытого ключа с помощью .Export ()
  • неожиданно ваши модульные тесты начнут давать сбой в более новой версии Windows, по-видимому, потому что вы не использовали правильные флаги

Да, они документированы и все (и некоторые из документов, кажется, имеют смысл), но почему это должно быть так сложно?

1 Ответ

0 голосов
/ 16 октября 2018

В основном, это должно быть так сложно сегодня, потому что это было так сложно вчера, и никто не придумал ничего более простого.

Я не могу придумать линейное повествование здесь, поэтому, пожалуйста, выдержитеткачество туда-сюда, что требуется.

Что такое файл PFX / PKCS # 12?

Хотя я не могу полностью сказать, каково происхождение PFX, в названиях есть ключ.из функций Windows для чтения и записи их: PFXImportCertStore и PFXExportCertStore .Они содержат множество отдельных сущностей (сертификаты, закрытые ключи и другие вещи), которые могут использовать идентификаторы свойств для взаимосвязи.Похоже, они разработаны как механизм экспорта / импорта для всего хранилища сертификатов, как и все CurrentUser \ My.Но поскольку одним из типов хранилищ является «хранилище памяти» (произвольная коллекция), импорт / экспорт в .NET имеет смысл, но возникают некоторые сложности (ранее .NET).

Закрытые ключи Windows

Windows поддерживает множество различных мест для закрытых ключей, но для устаревшего крипто API они сводятся к схеме адресации из 4 частей:

  • Имя провайдера криптографии
  • Имя контейнера ключей
  • Идентификатор, если это машинный ключ или пользовательский ключ
  • Идентификатор, если это ключ "подписи" или "обмен »ключом.

Это упрощено до трехэлементной схемы для CNG:

  • Имя механизма хранения
  • Имяключ
  • Идентификатор того, является ли это ключом, относящимся к компьютеру, или ключом, относящимся к пользователю.

Зачем нужен идентификатор компьютера или нет?

CAPI и CNG поддерживают непосредственное взаимодействие с именованными ключами.Итак, вы создаете ключ с именем «EmailDecryption».Другой пользователь в системе создает ключ с тем же именем.Должно ли это работать?Ну, наверное.Итак, хуз, это так!Отдельные ключи, потому что они хранятся в контекстах, привязанных к пользователю, который их создал.

Но теперь вам нужен ключ, который может использоваться несколькими пользователями.Это не то, что вы обычно хотите, так что это не по умолчанию.Это вариант.Флаг CRYPT_MACHINE_KEYSET рождается.

Я пойду дальше и скажу здесь, что я слышал, что прямое использование именованных ключей теперь не рекомендуется;команда CAPI / CNG очень предпочитает ключи с именами GUID и то, что вы взаимодействуете с ними через хранилища сертификатов.Но это часть эволюции.

Что делает импорт PFX?

PFXImportCertStore копирует все сертификаты из PFX в предоставленное хранилище.Он также импортирует ( CryptImportKey или BCryptImportKey , в зависимости от того, что он считает нужным).Затем для каждого импортированного ключа он находит (через значения свойств в PFX) соответствующий сертификат и устанавливает свойство в представлении хранилища сертификатов для «это мой 4-компонентный идентификатор» (ключи CNG просто устанавливают 4-й ключ).часть к 0);это действительно все, что сертификат знает о своем закрытом ключе.

(PFX - очень сложный формат файла, это описание верно при условии, что ни одна из "странных частей" не используется)

КлючВремя жизни

Закрытые ключи Windows живут вечно или до тех пор, пока кто-то их не удалит.

Поэтому, когда PFX импортирует их, они живут вечно.Это имеет смысл, если вы импортировали в CurrentUser \ My.Это не имеет смысла, если вы делали что-то временное.

.NET инвертирует отношения / делает это "слишком легким"

Дизайн Windows заключается (в основном) в том, что вы взаимодействуете с хранилищами сертификатов, ииз сертифицированных магазинов вы получаете сертификаты..NET появился позже, и (предположительно, основываясь на том, что на самом деле делали приложения), сделал сертификаты объектом верхнего уровня и хранит что-то вторичное.

Потому что сертификаты Windows (которые действительно "хранят"элементы сертификата ")" знают ", что их закрытый ключ, сертификаты .NET" знают ", что их закрытый ключ.

Да, но диспетчер сертификатов MMC говорит, что он может экспортировать сертификат со своим закрытым ключом (в PFX), почему конструктор сертификата не может принять эти байты в дополнение к формату «просто сертификат»?Итак, теперь это возможно.

Согласование времени жизни

Вы открываете несколько байтов как X509Certificate / X509Certificate2.Это PFX без пароля (любым из возможных способов).Вы видите, что он не тот, и позволяете сертификату отправляться на сборщик мусора.Этот закрытый ключ живет вечно, поэтому ваш жесткий диск медленно заполняется, а доступ к хранилищу ключей становится все медленнее и медленнее.Затем вы злитесь и переформатируете свой компьютер.

Это кажется плохим, так что .NET делает, когда (поле) сертификата получает сборщик мусора (фактически, завершен), он сообщает CAPI (или CNG)удалить ключ.Теперь все работает как положено, верно?Ну, до тех пор, пока программа не завершится ненормально.

О, вы добавили ее в постоянное хранилище?Но я собираюсь удалить закрытый ключ после того, как новый объект хранилища сертификатов «знает», как найти закрытый ключ.Это кажется плохим.

Введите X509KeyStorageFlags.PersistKeySet

PersistKeySet говорит: "не делайте этого, удаляя вещи".Это для случаев, когда вы намереваетесь добавить сертификат в X509Store.

Если вы хотите, чтобы такое же поведение без указания флага, вызывайте Environment.FailFast или отключите компьютер после выполнения импорта.

Об этом бите машины или пользователя

В .NET вы можете легко взять сумку с сертификатами в коллекции и позвонить по ней Export.Что делать, если у некоторых есть машинные ключи, а у других - пользовательские ключи?PFXExportCertStore на помощь.Когда машинный ключ экспортируется, он записывает идентификатор, который говорит, что это был машинный ключ, поэтому импорт возвращает его в то же место.

Ну, обычно.Возможно, вы экспортировали ключ компьютера с одной машины, и вы хотите просто проверить его как неадминистративный на другой машине.Хорошо, вы можете указать CRYPT_USER_KEYSET aka X509KeyStorageFlags.UserKeySet.

О, вы создали это как пользователь на одной машине, но хотите, чтобы это было как ключ машины на другой?Хорошо.CRYPT_MACHINE_KEYSET / X509KeyStorageFlags.MachineKeySet.

Действительно ли мне нужны "временные" файлы?

Если вы просто проверяете файлы PFX или иным образом хотите работать с ними на временной основе,зачем вообще писать ключ на диск?Хорошо, говорит Windows Vista, мы можем просто загрузить закрытый ключ непосредственно в объект криптографического ключа, и мы сообщим вам указатель.

PKCS12_NO_PERSIST_KEY / X509KeyStorageFlags.EphemeralKeySet

I 'Я хотел бы думать, что если бы в Windows была эта функция в NT4, это было бы по умолчанию для .NET.Сейчас это не может быть значением по умолчанию, потому что слишком многое зависит от того, как «обычный» импорт работает, чтобы определить, можно ли использовать закрытый ключ.

А как насчет последних двух?

Режим по умолчанию PFXImportCertStore заключается в том, что закрытые ключи не должны реэкспортироваться.Чтобы сказать, что это неправильно, вы можете указать CRYPT_EXPORTABLE / X509KeyStorageFlags.Exportable.

CAPI и CNG, оба поддерживают механизм, в котором программным ключам может потребоваться согласие или пароль перед использованием закрытого ключа (например,ПИН-код для смарт-карты), но вы должны указать это при первом создании (или импорте) ключа.Таким образом, PFXImportCertStore позволяет вам указать CRYPT_USER_PROTECTED (а .NET выставляет его как X509KeyStorageFlags.UserProtected).

Эти последние два действительно имеют смысл только для PFX «с одним закрытым ключом», потому что они применяются ко всем ключам,Они также не охватывают весь спектр опций, которые могли иметь исходные ключи ... и CNG, и CAPI поддерживают «архивируемые» ключи, что означает «экспортируемый один раз».Пользовательские списки ACL для ключей машины также не получают никакой поддержки в PFX.

Сводка

Для сертификата (или набора сертификатов) все просто.Как только закрытые ключи задействованы, все становится беспорядочным, а абстракция над сертификатом Windows (хранилищами) становится немного тоньше, и вам необходимо знать модель персистентности и модель хранения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...