В продолжении темы исследования COM интерфейсов CryptoAPI для управления службами Certificate Services предлагаю теперь разобрать вопросы KRA — Key Recovery Agents. Сначала напомню уже изученные темы по CryptoAPI:

И на сегодня наш план выглядит достаточно интересно:

  • Получение списка доступных KRA в лесу и просмотр их сертификатов
  • Получение списка KRA назначенных на сервере CA;
  • Назначение новых KRA для CA.

Получение списка доступных KRA в лесу

KRA используется для архивирования закрытых ключей сертификатов в БД CA. В случае если пользователь уничтожил свой закрытый ключ он может его восстановить. Для этого нужно обратиться к администратору CA для извлечения BLOB (Binary Large OBject) в файл. После чего агент восстановления (KRA) использует свой закрытый ключ для расшифровки закрытого ключа из BLOB'а. Учитывая, что я и не только уже рассматривали этот вопрос, я не буду пересказывать принцип работы Key Archival:

Все сертификаты KRA публикуются в forest naming configuration context партиции AD и реплицируется между всеми контроллерами в лесу. Публикация просисходит в точке:

CN=KRA, CN=Public Key Services, CN=Services, CN=Configuration, DC=ForestRootDomain

PS C:\> $ldap = [ADSI]"LDAP://CN=KRA, CN=Public Key Services, CN=Services, CN=Configuration, DC=contoso,dc=com" PS C:\> $ldap distinguishedName ----------------- {CN=KRA,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com} PS C:\> $kra = $ldap.psbase.children | %{$_} PS C:\> $kra distinguishedName ----------------- {CN=contoso-DC2-CA,CN=KRA,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com} {CN=Contoso CA,CN=KRA,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com}

Мы получили список CA в лесу и посмотрев каждый из них можем посмотреть сколько KRA сертификатов выпустил каждый CA:

PS C:\> $kra[1] | fl * objectClass : {top, msPKI-PrivateKeyRecoveryAgent} cn : {Contoso CA} userCertificate : {48 130 6 104 48 130 5 80 160 3 2 1 2 2 10 21 29 22 96 0 0 0 0 0 4 48 13 6 9 42 134 72 134 247 13 1 1 5 5 0 48 67 49 19 48 17 6 10 9 146 38 137 147 242 44 100 1 25 22 3 99 111 109 49 23 48 21 6 10 9 146 38 137 147 242 44 100 1 25 22 7 99 111 110 116 111 115 111 49 19 48 17 6 3 85 4 3 19 10 67 111 110 116 111 115 111 32 67 65 48 30 23 13 48 57 48 50 49 53 49 53 48 53 50 53 9 0 23 13 49 49 48 50 49 53 49 53 48 53 50 53 90 48 86 49 19 48 17 6 10 9 146 38 137 147 242 44 100 1 25 22 3 99 111 109 49 23 48 21 6 10 9 146 38 137 147 242 44 100 1 25 22 7 99 111 110 116 <...>

Свойство UserCertificate в виде массива может содержать сертификаты KRA в виде байтового массива. Например, указанный CA выпустил 2 сертификата KRA:

PS C:\> $kra[1].usercertificate.count 2

И обратившись к индексам этого свойства можно получить конкретные сертификаты: $kra[1].usercertificate[0]. Если CA не выпускал сертификаты для KRA, то свойство UserCertificate будет содержать число ноль:

PS C:\> $kra[0] | fl * objectClass : {top, msPKI-PrivateKeyRecoveryAgent} cn : {contoso-DC2-CA} userCertificate : {0} <...>

Поэтому для получения всех сертификатов KRA нужно пройтись по всем членам CN=KRA и выбрать из них ненулевые значения свойства UserCertificate. Если сертификатов больше, чем 1, то они будут храниться в этом свойстве в виде массива. Чтобы посмотреть сам сертификат, вы можете просто сохранить этот массив байтов в файл:

PS C:\> [System.IO.File]::WriteAllBytes("C:\kra.cer",$kra[1].usercertificate[1]) PS C:\> & .\kra.cer

Получение списка KRA назначенных на сервере CA

А теперь вернёмся к интерфейсу ICertAdmin2. С его помощью мы можем посмотреть количество агентов восстановления, которые назначены на CA и посмотреть их сертификаты. Однако, этот интерфейс имеет какой-то баг с PropID, которые связаны с KRA, о которых я писал в предыдущей статье, поэтому для получения этих данных мы будем использовать интерфейс ICertRequest3.

PS C:\> $CertRequest = New-Object -ComObject CertificateAuthority.Request.1 PS C:\> $CertRequest.GetCAProperty("dc1\contoso ca",0x18,0,1,0) 1 PS C:\> $CertRequest.GetCAProperty("dc2\contoso-dc2-ca",0x18,0,1,0) 0 PS C:\> $CertRequest.GetCAProperty("dc1\contoso ca",0x19,0,1,0) 1 PS C:\> $CertRequest.GetCAProperty("dc2\contoso-dc2-ca",0x19,0,1,0) 0

Мы видим, что на сервере DC1 назначен 1 агент восстановления, а на DC2 ни одного. Сегодня мы добавим агентов восстановления на DC2.

Примечание: чем отличаются KRACERTUSEDCOUNT и KRACERTCOUNT? KRACERTCOUNT показывает сколько всего KRA назначено на конкретном сервере CA. А KRACERTUSEDCOUNT показывает сколько из них будет использовать CA при архивации каждого закрытого ключа сертификата и это число может быть меньше, чем общее количество сертификатов KRA. В таком случае CA рандомно выбирает KRACERTUSEDCOUNT сертификатов и шифрует ими закрытый ключ. Например, KRACERTCOUNT = 5, а KRACERTUSEDCOUNT = 3, то CA при архивации ключа выберет рандомно 3 сертификата KRA из списка и зашифрует ими ключ. И только эти 3 агента восстановления могут восстановить ключ, а остальные 2 уже не смогут.

Получение списка KRA назначенных на сервере CA

Чтобы посмотреть сами сертификаты KRA, мы должны воспользоваться PropID = CR_PROP_KRACERT (0x1A).

И вот что мы увидим:

PS C:\> $CertAdmin.GetCAProperty("dc1\contoso ca",0x1A,0,3,0) -----BEGIN CERTIFICATE----- MIIGaDCCBVCgAwIBAgIKFR0WYAAAAAAABDANBgkqhkiG9w0BAQUFADBDMRMwEQYK CZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHY29udG9zbzETMBEGA1UE AxMKQ29udG9zbyBDQTAeFw0wOTAyMTUxNTA1MjVaFw0xMTAyMTUxNTA1MjVaMFYx EzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdjb250b3NvMQ4w DAYDVQQDEwVVc2VyczEWMBQGA1UEAxMNQWRtaW5pc3RyYXRvcjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJG7T5yMninhrkXFQU8WGUr5BYYUeOz10Rkn <...>

В нулевом индексе мы видим первый сертификат. Последующие будут храниться в других индексах:

$CertAdmin.GetCAProperty("dc1\contoso ca",0x1A,$Index,3,0)

Этот сертификат можно спокойно записать в файл и через GUI просмотреть его свойства. Но вообще это не родной формат сертификата KRA для данного интерфейса, поскольку добавлять сертификаты KRA на сервере CA нужно в ASN1 DER-encoded string формате. Т.е. Flags должен быть не 0, а 2:

$CertAdmin.GetCAProperty("dc1\contoso ca",0x1A,$Index,3,2)

и увидим примерно такое:

PS C:\> $kra = $CertAdmin.GetCAProperty("dc1\contoso ca",0x1a,0,3,2) PS C:\> $kra ?????A???` ?????c?♣??????????????????T???????????????????????????????????????T???????????????????????????????????????? ??ca♣??????☺??????????????????????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????☺????????Є?????????????????☻???????☻??????????????ЎЖ?????????????CA??????Ё????????????h??A??????? ??????????????????????????????????????????????╣???????????????????????????????????????????????????????????????????????? ?????????????????????C?cЁ??????C??????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????Х???CA?????Ё???????CA?????Б????CA??????????????????????a???☺???????????????????? ????????????????????????????????????c?????????????????????????????????????H╝??????????????????{?????????????

выглядит весьма уныло, но вот в таком формате и надо записывать сертификаты агентов восстановления в CA.

Назначение новых KRA для CA

Когда мы рассмотрели основные моменты связанные с агентами восстановления в контексте CryptoAPI, мы можем приступить к финальной части — назначению новых агентов восстановления. В принципе, здесь нет ничего сложного, поскольку для добавления KRA нужно сделать 5 вещи:

  1. Получить массив байтов, которые бы представляли сертификат агента восстановления откуда угодно. Хоть из AD, хоть из файла сертификата;
  2. Используя специальный конвертер, разобрать этот массив на пары байтов, сконвертировать эти пары в little-endian hex строку, получить десятичное представление этой hex-строки и получить итоговую символьную строку;
  3. Записать эту строку используя метод SetCAProperty();
  4. Задать новое количество используемых агентов восстановления;
  5. Перезапустить службу CA.

Первый этап у нас уже пройден, поскольку у нас уже есть такой массив в AD. Если сертификата агента восстановления нет в AD, то можно его получить из файла:

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import(".\desktop\kra.cer")
$bytes = $cert.RawData

и переменная $bytes будет содержать такой же байтовый массив.

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

function ConvertTo-DERstring ([byte[]]$bytes) {
    # создаём объект StringBuilder, который нам будет собирать конечную символьную строку
    $SB = New-Object System.Text.StringBuilder
    # преобразовываем каждый байт в его hex значение
    $bytes1 = $bytes | %{"{0:X2}" -f $_}
    # циклом перебираем каждую пару байт
    for ($n = 0; $n -lt $bytes1.count; $n = $n + 2) {
        # переставляем элементы пары местами, чтобы получить little-endian hex-строку
        # после чего получаем десятичное представление этой строки и получаем Unicode
        # символ, который соответствует этому десятичному значению.
        [void]$SB.Append([char](Invoke-Expression 0x$(($bytes1[$n+1]) + ($bytes1[$n]))))
    }
    $SB.ToString()
}

А дальше уже по накатанной дороге:

[Administrator] # создаём COM объект ICertAdmin2 [Administrator] $CertAdmin = new-object -com certificateauthority.admin.1 [Administrator] # выбираем все Enterprise CA [Administrator] $ldap = [ADSI]"LDAP://CN=KRA, CN=Public Key Services, CN=Services, CN=Configuration, DC=contoso,dc=com" [Administrator] $kra = $ldap.psbase.children | %{$_} [Administrator] # сразу конвертируем все сертификаты в DER-encoded string [Administrator] $kra1 = ConvertTo-DERstring $kra[1].usercertificate[0] [Administrator] $kra2 = ConvertTo-DERstring $kra[1].usercertificate[1] [Administrator] # можем убедиться на месте, что строка имеет ожидаемый вид [Administrator] $kra2 ?????A???E ?????c?♣??????????????????T???????????????????????????????????????T???????????????????????????????????????? ??ca♣??????☺????????????????????????????K?????????????????????????????????????????????т???????????????????????????????? ??????????????????????☺????????Є?????????????????☻???????☻??????????????ЎЖ?????????????CA??????Ё????????????h??A??????? ??????????????????????????????????????????????╣???????????????????????????????????????????????????????????????????????? ?????????????????????C?cЁ??????C??????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????Х???CA?????Ё???????CA?????Б????CA??????????????????????a???☺???????????????????? ???????????????????????????????????????????????????????????????????????????????????????????????????????????? [Administrator] # и записываем первую строку сертификат агента восстанвовления в нулевой индекс [Administrator] $CertAdmin.SetCAProperty("dc2\contoso-dc2-ca",0x1a,0,3,$kra1) [Administrator] # все последующие строки сертификатов записываются в последующие индексы массива [Administrator] $CertAdmin.SetCAProperty("dc2\contoso-dc2-ca",0x1a,1,3,$kra2) [Administrator] # используем PropID = KRACERTUSEDCOUNT (0x18), чтобы сказать сколько у нас будет использоваться агентов [Administrator] # я буду их использовать все [Administrator] $CertAdmin.SetCAProperty("dc2\contoso-dc2-ca",0x18,0,1,2) [Administrator] # перезапускаем службу CertSvc [Administrator] $wmi = gwmi win32_service -comp dc2 -filter "name='certsvc'" [Administrator] [void]$wmi.StopService() [Administrator] [void]$wmi.StartService() [Administrator] # и проверяем нашу работу: [Administrator] $CertReq = new-object -com certificateauthority.request.1 [Administrator] $CertReq.GetCAProperty("dc2\contoso-dc2-ca",0x18,0,1,0) 2 [Administrator] $CertReq.GetCAProperty("dc2\contoso-dc2-ca",0x19,0,1,0) 2 [Administrator]

всё.

Friday, November 20, 2009 6:40:36 PM (FLE Standard Time, UTC+02:00)   Comments [0]    

 

OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Live Comment Preview
 · 
All content © 2008 - 2010, Vadims Podāns
"Spaces" Theme provided by: Vadims Podāns
About


E-mail - Send mail to the author(s)
Live Messenger -
My former blog -
For english language visitors

Translate via Google Translator

Библиотека
Календарик
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Карта расположения посетителей
Favorites

Домашняя страничка Теры Патрик

Disclaimer
Вся информация на сайте предоставляется на условиях «как есть», без предоставления каких-либо гарантий и прав.

При использовании материалов c данного сайта ссылка на оригинальный источник обязательна.