Примечание: данный материал публикуется на правах ТЗ (ТЗ — Тайное Знание) и обязателен для знания администраторам PKI.
В предыдущей части (Certificate chaining engine в PowerShell) мы рассмотрели реализацию certificate chaining engine в .NET в виде класса X509Chain. Но этот рассказ был бы неполным, если мы не поговорили про CAPICOM.Chain. Хоть Microsoft рекомендует использовать .NET, а не CAPICOM для решения данной задачи, я считаю необходимым осветить этот вопрос. Для начала начнём с реализации CAPICOM в PowerShell. По непонятным мне пока причинам мне не удалось завести его в PowerShell на системах Windows Vista и выше, поэтому примеры буду приводить на Windows Server 2003.
PS G:\> $chain = New-Object -ComObject "CAPICOM.Chain" PS G:\> $chain Certificates ------------ PS G:\> $chain | gm -MemberType methods TypeName: System.__ComObject#{ca65d842-2110-4073-aee3-d0aa5f56c421} Name MemberType Definition ---- ---------- ---------- ApplicationPolicies Method IOIDs ApplicationPolicies () Build Method bool Build (ICertificate) CertificatePolicies Method IOIDs CertificatePolicies () ExtendedErrorInfo Method string ExtendedErrorInfo (int) PS G:\>
Так же, как и в .NET у нас есть метод Build(), который запускает certificate chaining engine для указанного сертификата. Но это COM объект и X509Certificate2 объекты не принимает. Поэтому мы средствами этого же CAPICOM получим нужный объект сертификата:
PS G:\> $store = New-Object -ComObject "CAPICOM.Store" PS G:\> $store.Open(2,"my",128) PS G:\> $cert = @() PS G:\> $store.Certificates | %{$cert += $_} PS G:\> $cert = $cert[1] PS G:\> $cert Version : 3 SerialNumber : 167D6D32000000000011 SubjectName : CN=Administrator, CN=Users, DC=sysadmins, DC=lv IssuerName : CN=sysadmins-LV-CA, DC=sysadmins, DC=lv ValidFromDate : 2009.08.07. 16:09:56 ValidToDate : 2010.08.07. 16:09:56 Thumbprint : 1FA71B51BCE461BEE24B11AA9EF855ED00DFDFD4 Archived : False PrivateKey : PS G:\>
Вот такой объект сертификата мы получили. Вот его и пропустим через метод Build():
PS G:\> $chain.Build($cert) False PS G:\> $chain.Status() 32 PS G:\> $chain.Certificates Version : 3 SerialNumber : 167D6D32000000000011 SubjectName : CN=Administrator, CN=Users, DC=sysadmins, DC=lv IssuerName : CN=sysadmins-LV-CA, DC=sysadmins, DC=lv ValidFromDate : 2009.08.07. 16:09:56 ValidToDate : 2010.08.07. 16:09:56 Thumbprint : 1FA71B51BCE461BEE24B11AA9EF855ED00DFDFD4 Archived : False PrivateKey : Version : 3 SerialNumber : 3DFFAF914D613282427BD591C1FB586D SubjectName : CN=sysadmins-LV-CA, DC=sysadmins, DC=lv IssuerName : CN=sysadmins-LV-CA, DC=sysadmins, DC=lv ValidFromDate : 2009.08.06. 10:21:01 ValidToDate : 2014.08.06. 10:30:54 Thumbprint : E82ACC45841280DDEAB9F7847418FA26354457A7 Archived : False PrivateKey : PS G:\> $chain.ApplicationPolicies() Name FriendlyName Value ---- ------------ ----- 123 Smart Card Logon 1.3.6.1.4.1.311.20.2.2 101 Client Authentication 1.3.6.1.5.5.7.3.2 PS G:\>
Метод вернул False, т.е. наш сертификат не прошёл проверку. Свойство Certificates содержит все сертификаты в текущей цепочке. А метод ApplicationPolicies() показал Application Policies (в прошлом EKU). Ну и метод Status() вернул код ошибки. Все коды ошибок расписаны в описании самого метода. Т.е. ошибка 32 по табличке означает:
CAPICOM_TRUST_IS_UNTRUSTED_ROOT (&H00000020) — The certificate or certificate chain is based on an untrusted root.
Особо углубляться дальше я смысла не вижу, поскольку используя эти примеры можно поупражняться в других задачах с использованием CAPICOM. А вместо этого, мы разберём кое-какие неочевидные, но очень важные вещи.
Когда вышел Remote Desktop Connection 7.0 (который поставляется вместе с Windows 7), Александр Станкевич (MVP: Enterprise Security) заметил очень плохую особенность с ним, а именно — рандомно пропал доступ к терминальным серверам, которые используют SSL для терминальных подключений. В ходе множества проверок было констатировано:
RDP клиент мотивировал отказ в подключении следюущим: «RDP клиент не смог проверить сертификат на отзыв». Причём подключение с предыдущих версий RDC, а так же подключение к TS Web Access через IE было успешным. Как выяснилось на днях, причина была в том, что в новом RDC был изменён алгоритм certificate chaining engine и новая версия RDC больше не доверяла корневым сертификатам в пользовательском хранилище. Переустановка корневого сертификата в компьютерное хранилище решала проблему RDC 7. Но, как я говорил, в Windows 7/2008 R2 было изменено поведение certificate chaining engine в реализации X509Chain. Продемонстрирую небольшую табличку, которая покажет доверие пользовательским корневым сертификатам в CAPICOM и .NET реализациях certificate chaining engine для различных операционных систем:
X509Chain (.NET) | CAPICOM.Chain (CryptoAPI) | |
Windows XP | :yes: | :no: |
Windows Server 2003 | :yes: | :no: |
Windows Vista | :yes: | :no: |
Windows Server 2008 | :yes: | :no: |
Windows 7 | :no: | :no: |
Windows Server 2008 R2 | :no: | :no: |
Таблица доверия пользовательскким корневым сертификатам различными движками построения цепочки сертификатов
Следует учитывать, что различные приложения могут использовать свой движок для построения цепочек сертификатов, как RDC 7.0 и PKIView.msc использует CAPICOM, а PowerShell — X509Chain. Однако, у меня есть уверенность, что существует ещё одна реализация этого движка, которую использует Internet Explorer. Это только мои догадки, но они основаны на том, что Internet Explorer (кроме Windows 7 и выше) использует пользовательский контейнер для проверки SSL веб-сайтов, т.е. по симптомам похоже на X509Chain. Однако, этот класс появился только в .Net Framework 2.0, которого, к примеру в оригинальной инсталляции Windows XP/2003 не было. Либо, как вариант, есть возможность настраивать этот момент в каждой реализации движка построения цепочек, но я пока не нашёл как. Это пока всё, что у меня есть по этому поводу.
> Когда вышел Remote Desktop Connection 7.0 (который поставляется вместе с Windows 7) RDP там - 6.1.7 > Александр Станкевич (MVP: Enterprise Security) заметил очень плохую особенность с ним Потому что раньше добавлял в пользовательское хранилище корневые сертификаты. А так делать нельзя. Пользователь by design не может выбирать стартовую точку доверия в CCE.
так речь идёт не про сам RDP. А именно про сам клиент RDC, который входит в поставку Windows 7. > Пользователь by design не может выбирать стартовую точку доверия в CCE. да, в Windows 7 пользователь больше не может выбирать конечную (ведь стартовая - это сам проверяемый сертификат). Но я сегодня лично убедился в Windows Server 2003, что в зависимости от метода CCE (.Net или CAPICOM) можно получить разные результаты. Всё же, я склоняюсь к тому, что CAPICOM реализован более правильно с точки зрения безопасности, потому что он всегда игнорирует пользовательские корневые сертификаты.
На самом деле, алгоритм не изменился ни разу, а просто проверка на отозванность сертификата стала обязательной;). Например, если мы включим на сервере обязательное требование NLA, то мы увидим точно такую же ошибку "Не удалось проверить не отозван ли сертификат." (как-то так) и на XP SP3 с RDC 6.1.
С NLA не пробовал проверять. А на счёт обязательной проверки отзыва, надо посмотреть как дела обстояли с предыдущими клиентами, например 5.2. Помнится, они тоже требовали такой проверки.
С RDC 5.2 можно подключиться даже в том случае, когда корню доверия нет вообще! Правда, эксперимент показал, что в случае невозможности проверить цепочку (например, недоступность корня через AIA), подключиться не получится.
Comments: