Contents of this directory is archived and no longer updated.

Я вчера в статье Certificate Trust List (CTL) в PowerShell показал основные принципы, как работать с CTL в PowerShell. Сегодня я продолжу тему и покажу, как можно вытащить доверенные корневые сертификаты из ресурсов Crypt32.dll и из интернетов. Но для начала, Crypt32.dll

Вот как они выглядят в каком-нибудь редакторе ресурсов:

Crypt32.dll resources

Примечание: в Windows XP и Windows Server 2003 этих ресурсов не будет. Они есть только в системах начиная с Windows Vista.

Выглядит не очень презентабельно, просто они хранятся там в сериализированном виде (serialized store). Нас будет интересовать AUTHROOTS и UPDROOTS. В WinAPI есть целая вязанка функций, которые отвечают за работу с ресурсами: Resource Functions. Нас будет интересовать только следующие функции:

  • LoadLibraryEx — эта функция загружает библиотеку в память;
  • FindResource — эта функция ищет требуемый ресурс;
  • SizeofResource — вычисляем размер ресурса, чтобы выделить под него буфер;
  • LoadResource — загружает ресурс в буфер, созданный на предыдущем этапе;
  • FreeLibrary — этой функцией завершаем работу (выгружаем библиотеку из памяти).

И вот сигнатуры функций:

$signature = @"
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibraryEx(
    String lpFileName,
    IntPtr hFile,
    UInt32 dwFlags
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr FindResource(
    IntPtr hModule,
    int lpID,
    string lpType
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint SizeofResource(
    IntPtr hModule,
    IntPtr hResInfo
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr LoadResource(
    IntPtr hModule,
    IntPtr hResInfo
);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool FreeLibrary(
    IntPtr hModule
);
"@
Add-Type -MemberDefinition $signature -Namespace PKI -Name Kernel32

А дальше всё просто:

$path = $Env:SystemRoot + "\System32\crypt32.dll"
# загружаем Crypt32.dll в память
$hModule = [PKI.Kernel32]::LoadLibraryEx($path,[IntPtr]::Zero,0x2)
# ищем ресрус AUTHROOTS под номером 1010
$hResInfo = [PKI.Kernel32]::FindResource($hModule,1010,"AUTHROOTS")
# вычисляем размер ресурса для создания буфера в managed memory
$size = [PKI.Kernel32]::SizeOfResource($hModule, $hResInfo)
# загружаем ресурс в unmanaged memory и получаем pointer на него
$resource = [PKI.Kernel32]::LoadResource($hModule, $hResInfo)
# создаём буфер для ресурса
$bytes = New-Object byte[] -ArgumentList $size
# и маршалером копируем ресурс из неуправляемой памяти в наш буфер.
# данные будут представлять собой serialized certificate store.
[Runtime.InteropServices.Marshal]::Copy($resource, $bytes, 0, $size)
# ход конём: создаём объект X509Certificate2Collection, который поддерживает
# сериализированные хранилища SST
$AUTHROOTS = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
# импортируем наши байтики в X509Certificate2Collection
$AUTHROOTS.Import($bytes)
# повторяем процедуру для UPDROOTS
$hResInfo = [PKI.Kernel32]::FindResource($hModule,1011,"UPDROOTS")
$size = [PKI.Kernel32]::SizeOfResource($hModule, $hResInfo)
$resource = [PKI.Kernel32]::LoadResource($hModule, $hResInfo)
$bytes = New-Object byte[] -ArgumentList $size
[Runtime.InteropServices.Marshal]::Copy($resource, $bytes, 0, $size)
$UPDROOTS = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$UPDROOTS.Import($bytes)
[PKI.Kernel32]::FreeLibrary($hModule)

И вот что у нас на выходе:

[↓] [vPodans] $AUTHROOTS[0..5]

Thumbprint                                Subject
----------                                -------
879F4BEE05DF98583BE360D633E70D3FFE9871AF  CN=NetLock Uzleti (Class B) Tanusitvanykiado, OU=Tanusitvanykiadok, O=NetL...
E12DFB4B41D7D9C32B30514BAC1D81D8385E2D46  CN=UTN-USERFirst-Object, OU=http://www.usertrust.com, O=The USERTRUST Netw...
0483ED3399AC3608058722EDBC5E4600E3BEF9D7  CN=UTN-USERFirst-Hardware, OU=http://www.usertrust.com, O=The USERTRUST Ne...
58119F0E128287EA50FDD987456F4F78DCFAD6D4  CN=UTN - DATACorp SGC, OU=http://www.usertrust.com, O=The USERTRUST Networ...
D29F6C98BEFC6D986521543EE8BE56CEBC288CF3  E=certificate@trustcenter.de, OU=TC TrustCenter Class 4 CA, O=TC TrustCent...
838E30F77FDD14AA385ED145009C0E2236494FAA  E=certificate@trustcenter.de, OU=TC TrustCenter Class 2 CA, O=TC TrustCent...


[↓] [vPodans] $UPDROOTS[0..5]

Thumbprint                                Subject
----------                                -------
132D0D45534B6997CDB2D5C339E25576609B5CC6  CN=VeriSign Class 3 Public Primary Certification Authority - G3, OU="(c) 1...
204285DCF7EB764195578E136BD4B7D1E98E46A5  CN=VeriSign Class 1 Public Primary Certification Authority - G3, OU="(c) 1...
801D62D07B449D5C5C035C98EA61FA443C2A58FE  CN=Entrust.net Certification Authority (2048), OU=(c) 1999 Entrust.net Lim...
8939576E178DF705780FCC5EC84F84F6253A4893  CN=Entrust.net Secure Server Certification Authority, OU=(c) 2000 Entrust....
7030AABF8432A800666CCCC42A887E42B7553E2B  CN=eSign Imperito Primary Root CA, OU=Public Secure Services, O=eSign Aust...
C73026E325FE21916B55C4B53A56B13DCAF3D625  CN=Gatekeeper Root CA, OU=Gatekeeper PKI, O=eSign Australia


[↓] [vPodans]

Я показал только по 6 первых элементов из каждого ресурса. На самом деле их там чуточку больше:

[↓] [vPodans] $AUTHROOTS.Count
87
[↓] [vPodans] $UPDROOTS.Count
165

С этим списком вы уже можете делать что хотите. Единственное, что я могу посоветовать — не пропускайте их без лишней надобности через certificate chaining engine (это включает как вызов метода Verify(), использование в X509Chain или просмотр сертификата в UI, т.к. это тоже запускает certificate chaining engine), потому что они будут устанавливаться в хранилище. А оно вам надо?

Однако, этот список не самый актуальный. Если не ошибусь, он обновляется (в самой библиотеке) с выходом сервис-пака. А список членов программы изменяется почаще (см: Windows Root Certificate Program Members). И вот пруф номер 2:

[↓] [vPodans] $UPDROOTS | ?{$_.thumbprint -eq "C060ED44CBD881BD0EF86C0BA287DDCF8167478C"}

Thumbprint                                Subject
----------                                -------
C060ED44CBD881BD0EF86C0BA287DDCF8167478C  E=info@diginotar.nl, CN=DigiNotar Root CA, O=DigiNotar, C=NL


[↓] [vPodans] dir cert:\CurrentUser\Disallowed\C060ED44CBD881BD0EF86C0BA287DDCF8167478C


    Directory: Microsoft.PowerShell.Security\Certificate::CurrentUser\Disallowed


Thumbprint                                Subject
----------                                -------
C060ED44CBD881BD0EF86C0BA287DDCF8167478C  E=info@diginotar.nl, CN=DigiNotar Root CA, O=DigiNotar, C=NL


[↓] [vPodans]

А, ведь, DigiNotar выпилен из программы.

На практике это происходит вот как: клиент скачивает самый свежий authrootstl.cab, списывает себе хеши и выпиливает все сертификаты из Third-Party CAs, чьи хеши не представлены в CTL. А если в CTL есть хеш нового участника, а сертификата у клиента нету? Он его должен где-то взять и заныкать до лучших времён (т.е. доставит в хранилище по первому требованию). Берёт его он примерно вот здесь: http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/<Thumbprint>.crt

Возьмём какой-нибудь сертификат (из тех, что есть в Crypt32.dll) и поштриноль:

[↓] [vPodans] $rm = Invoke-RestMethod "http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/879
F4BEE05DF98583BE360D633E70D3FFE9871AF.crt"
[↓] [vPodans] [byte[]]$rm = $rm.ToCharArray() | %{[byte]$_}
[↓] [vPodans] New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 (,$rm)

Thumbprint                                Subject
----------                                -------
879F4BEE05DF98583BE360D633E70D3FFE9871AF  CN=NetLock Uzleti (Class B) Tanusitvanykiado, OU=Tanusitvanykiadok, O=NetL...


[↓] [vPodans]

Командлет Invoke-RestMethod появился в PowerShell 3.0 и является простым враппером для WebRequestCmdlet. Т.е. при наличии интернетов, вы можете взять authrootstl.cab и через Invoke-RestMethod или Invoke-WebRequest накачать себе сертификатов под завязку :-)


Share this article:

Comments:

www.google.com/accounts/o8/id?id=AItOawlBmWdzpHX3YB7CilTbWeupNTMV2NeN_b0

Что-то я не понял, а зачем это? Что с ними потом можно сделать? Закрытых ключей же с ними не будет?

Vadims Podāns

А кто сказал, что это делается с целью извлечения ключей? Я пост написал не просто так, а потому что заметил, что народ спрашивает (особенно когда в их компаниях действует строгая политика аудита).

Comments are closed.