Certificate chaining engine в PowerShell – PKI Extensions

Certificate chaining engine в powershell – pki extensions

Я предлагаю снова поговорить о certificate chaining engine, о котором мы уже говорили в посте Certificate Chaining Engine — как это работает но в рамках его реализации в .NET и PowerShell. В Windows есть несколько реализаций этого chaining engine. Самые популярные:

CAPICOM — вещь несколько стрёмная и её лучше избегать. Тем более мне не удалось завести его в Vista/Windows 7. Реализация в .NET в виде X509Chain ничуть не хуже, но, в то же время, проще. Итак, предлагаю начать с создания этого объекта с помощью New-Object:

[↓] [vPodans] $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
[↓] [vPodans] $chain

                 ChainContext ChainPolicy                   ChainStatus                   ChainElements
                 ------------ -----------                   -----------                   -------------
                            0 System.Security.Cryptograp... {}                            {}


[↓] [vPodans] $chain | gm -membertype methods


   TypeName: System.Security.Cryptography.X509Certificates.X509Chain

Name        MemberType Definition
----        ---------- ----------
Build       Method     bool Build(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
Reset       Method     System.Void Reset()
ToString    Method     string ToString()


[↓] [vPodans]

Здесь видно, что метод, который будет строить и проверять цепочку будет называться Build() и в качестве аргумента этот метод принимает только объекты x509Certificate2, а возвращать объект типа Boolean — True/False. Объекты такого типа можно найти в провайдере Certififcates (просто выполнить dir cert:storecontainer) или импортировать из файла — Импорт сертификатов в PowerShell. Но сначала мы посмотрим, что здесь можнол настроить. А настроить можно ChainPolicy, представляющий собой объект X509ChainPolicy. Эта политика позволяет задавать порядок проверки отзыва сертификатов, соответствие сертификата каким-то certificate policy, наличие определённых application policy (в прошлом известен нам как EKUExtended Key Usage) и некритичность каких-то ошибок. Мы всё разбирать не будем, а только основное:

[↓] [vPodans] $chain.ChainPolicy


ApplicationPolicy   : {}
CertificatePolicy   : {}
RevocationMode      : Online
RevocationFlag      : ExcludeRoot
VerificationFlags   : NoFlag
VerificationTime    : 17.10.2009 20:35:17
UrlRetrievalTimeout : 00:00:00
ExtraStore          : {}



[↓] [vPodans]

Первое, что может быть интересным — Revocation Mode, который задаёт режим проверки отзыва и может иметь 3 вполне понятных значения, которые перечислены в X509RevocationMode:

[↓] [vPodans] [System.Enum]::GetNames([system.security.cryptography.x509certificates.x509revocationmode])
NoCheck
Online
Offline

Тут очень просто:

  • NoCheck — проверяет цепочку сертификатов без проверки на отзыв любых сертификатов в цепочке;
  • Online — проверяет сертификаты в цепочке скачивая новые списки CRL из свойства CDP сертификата, игнорируя локальный кеш CRL (используется по умолчанию, как это видно в просмотре свойств ChainPolicy)
  • Offline — проверяет сертификаты на отзыв с использованием кешированного CRL (если есть).

Если проверяем сертификаты на отзыв, то мы можем выбрать что именно будем проверять и этот выбор перечислен в X509RevocationFlag:

[↓] [vPodans] [System.Enum]::GetNames([system.security.cryptography.x509certificates.x509revocationflag])
EndCertificateOnly
EntireChain
ExcludeRoot

и здесь тоже всё достаточно понятно:

  • EndCertificateOnly — проверяет на отзыв только сам проверяемый сертификат. Остальные сертификаты в цепочке не проверяются;
  • EntireChain — проверяет на отзыв абсолютно все сертификаты в цепочке включая корневой сертификат. Правила хорошего тона диктуют нам не включать в корневой сертификат CA поля CDP и AIA, поскольку это лишено смысла и в большинстве случаев с этим флагом вы будете получать невалидную цепочку;
  • ExcludeRoot — проверяет на отзыв все сертификаты в цепочке, кроме корневого сертификата, что есть религионзно правильно и этот флаг установлен по умолчанию.

Следующий момент определяет флаги проверки, т.е. по каким именно критериям будет проверяться цепочка сертификатов:

[↓] [vPodans] [System.Enum]::GetNames([system.security.cryptography.x509certificates.x509verificationflags])
NoFlag
IgnoreNotTimeValid
IgnoreCtlNotTimeValid
IgnoreNotTimeNested
IgnoreInvalidBasicConstraints
AllowUnknownCertificateAuthority
IgnoreWrongUsage
IgnoreInvalidName
IgnoreInvalidPolicy
IgnoreEndRevocationUnknown
IgnoreCtlSignerRevocationUnknown
IgnoreCertificateAuthorityRevocationUnknown
IgnoreRootRevocationUnknown
AllFlags

Эти флаги так же достаточно понятны и подробно разжёваны в перечислении X509VerificationFlags.

Примечание: эти флаги показывают что будет исключено из проверки, а не наоборот. По умолчанию проверяется всё (установлен NoFlag).

Как можно задавать эти флаги и режимы, если есть такая потребность? Можно пойти двумя способами — правильным и неправильным, хотя оба рабочие:

[↓] [vPodans] # правильный метод:
[↓] [vPodans] $revflag = [System.Security.Cryptography.X509Certificates.X509RevocationFlag]::EndCertificateOnly
[↓] [vPodans] $chain.ChainPolicy.RevocationFlag = $revflag
[↓] [vPodans] $chain.ChainPolicy


ApplicationPolicy   : {}
CertificatePolicy   : {}
RevocationMode      : Online
RevocationFlag      : EndCertificateOnly
VerificationFlags   : NoFlag
VerificationTime    : 17.10.2009 20:35:17
UrlRetrievalTimeout : 00:00:00
ExtraStore          : {}



[↓] [vPodans] # неправильный метод, но мне он нравится
[↓] [vPodans] $chain.ChainPolicy.RevocationFlag = "excluderoot"
[↓] [vPodans] $chain.ChainPolicy


ApplicationPolicy   : {}
CertificatePolicy   : {}
RevocationMode      : Online
RevocationFlag      : ExcludeRoot
VerificationFlags   : NoFlag
VerificationTime    : 17.10.2009 20:35:17
UrlRetrievalTimeout : 00:00:00
ExtraStore          : {}



[↓] [vPodans]

В принципе, все эти enumeration можно просто указывать в виде строки, а PowerShell уже сам подобъёт его под нужный тип.

Про сертификаты:  КриптоПро | Сервис электронной подписи

Примечание: флаги проверки на отзыв можно указывать только по одному, а флаги исключений можно перечислять через запятую. Это видно по названию класса: если класс указан в единственном числе (X509RevocationFlag), то и значение можно указать только одно, а если во множественном числе (X509VerificationFlags), то их можно указать несколько через запятую.

В принципе, можно делать проверку:

[↓] [vPodans] $valid = (dir cert:currentusermy)[1]
[↓] [vPodans] $invalid = (dir cert:currentusermy)[0]
[↓] [vPodans] $chain.Build($valid)
True
[↓] [vPodans] $chain.ChainElements | select -expand certificate

Thumbprint                                Subject
----------                                -------
986D375362652FE9E39BA4D042A6B8BA75745998  CN=Administrator, CN=Users, DC=sysadmins, DC=lv
E82ACC45841280DDEAB9F7847418FA26354457A7  CN=sysadmins-LV-CA, DC=sysadmins, DC=lv


[↓] [vPodans]

Я из локального хранилища взял заведомо хороший сертификат и плохой (разумеется, это сертификат с сайта БиЛайн :-)). Метод Build() вернул True, что означает успешную проверку всей цепочки моего сертификата до доверенного корня. А вот что случилось с сертификатом билайна:

[↓] [vPodans] $chain.reset()
[↓] [vPodans] $chain.Build($invalid)
False
[↓] [vPodans] $chain.ChainElements | select -expand certificate

Thumbprint                                Subject
----------                                -------
EB74DA32E865C78FCB853DDA5FE45962098E1B3B  CN=trust.beeline.ru, OU=DIT, O=Vimpelcom, L=Moscow, S=Moscow, C=RU


[↓] [vPodans] $chain.ChainStatus

                                                     Status StatusInformation
                                                     ------ -----------------
                                               PartialChain Sertificesanas kedi nevareja veidot pie uzticamas saknes...
                                    RevocationStatusUnknown Atsauksanas funkcija nevareja parbaudit sertifikata atsa...
                                          OfflineRevocation Atsauksanas funkcija nevareja parbaudit atsauksanu, jo a...


[↓] [vPodans] $chain.ChainStatus | %{$_.statusinformation.trim()}
Sertificesanas kedi nevareja veidot pie uzticamas saknes iestades.
Atsauksanas funkcija nevareja parbaudit sertifikata atsauksanu.
Atsauksanas funkcija nevareja parbaudit atsauksanu, jo atsauksanas serveris bija bezsaiste.
[↓] [vPodans]

Поскольку при каждой проверке сертификаты в ChainElements накапливаются, то после каждой проверки следует очищать объект методом Reset(). Как и следовало ожидать, сертификат билайна вернул False, показывая, что цепочка у этого сертификата имеет проблемы. В случае неуспешной проверки, будет заполняться свойство ChainStatus. Данное свойство содержит все ошибки, которые были костатированы при проверке цепочки. Для меня пока непонятным стал факт, что ошибки он написал на латышском языке, хотя я его об этом не просил. Откуда он это взял — непонятно, но он сказал, что не смог построить цепочку до доверенного корня и функция проверки отзыва провалилась по всем статьям, поскольку пути в CDP сертификата нерабочие.

Примечание: обязательно следует учитывать тот факт, что при построении цепочки сертификатов и проверке доверия класс X509Chain в Windows 7 и Windows Server 2008 R2 работает в контексте LocalSystem и всегда игнорирует пользовательские контейнеры Trusted Root Certification Authorities. Поэтому если корень цепочки не заканчивается на одном из сертификатов Trusted Root CAs хранилища LocalMachine, то цепочка будет считаться недоверенной. Для предыдущих ОС цепочка может заканчиваться на пользовательском хранилище Current User.

В принципе это всё, что вам следует знать про реализацию certificate chaining engine в .NET и его использование в PowerShell. В качестве бонуса прилагаю скрипт для проверки цепочки сертификатов:

functionTest-Certificate{[CmdletBinding()]param([Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)]$Certificate,[System.Security.SecureString]$Password,[ValidateSet("NoCheck","Online","Offline")][string]$CRLMode="Online",[ValidateSet("EndCertificateOnly","EntireChain","ExcludeRoot")][string]$CRLFlag="ExcludeRoot",[ValidateSet("AllFlags","AllowUnknownCertificateAuthority","NoFlag","IgnoreNotTimeValid","IgnoreCtlNotTimeValid","IgnoreNotTimeNested","IgnoreInvalidBasicConstraints","IgnoreWrongUsage","IgnoreInvalidName","IgnoreInvalidPolicy","IgnoreEndRevocationUnknown","IgnoreCtlSignerRevocationUnknown","IgnoreCertificateAuthorityRevocationUnknown","IgnoreRootRevocationUnknown")][string[]]$VerificationFlags="NoFlag")begin{$cert=New-ObjectSystem.Security.Cryptography.X509Certificates.X509Certificate2$chain=New-ObjectSystem.Security.Cryptography.X509Certificates.X509Chain$chain.ChainPolicy.RevocationFlag=$CRLFlag$chain.ChainPolicy.RevocationMode=$CRLMode$chain.ChainPolicy.VerificationFlags=$VerificationFlagsfunction_getstatus_($status,$chain,$cert){if($status){Write-HostCurrentcertificate$cert.SerialNumberchainandrevocationstatusisvalid-ForegroundColorGreen}else{Write-Warning"Current certificate $($cert.SerialNumber) chain is invalid due of the following errors:"$chain.ChainStatus|%{Write-Host$_.StatusInformation.trim()-ForegroundColorRed}}}}process{if($_-is[System.Security.Cryptography.X509Certificates.X509Certificate2]){$status=$chain.Build($_)_getstatus_$status$chain$_}else{if(!(Test-Path$Certificate)){Write-Warning"Specified path is invalid";return}else{if((Resolve-Path$Certificate).Provider.Name-ne"FileSystem"){Write-Warning"Spicifed path is not recognized as filesystem path. Try again";return}else{$Certificate=gi$(Resolve-Path$Certificate)switch-regex($Certificate.Extension){".CER|.DER|.CRT"{$cert.Import($Certificate.FullName)}".PFX"{if(!$Password){$Password=Read-Host"Enter password for PFX file $certificate"-AsSecureString}$cert.Import($Certificate.FullName,$password,"UserKeySet")}".P7B|.SST"{$cert=New-ObjectSystem.Security.Cryptography.X509Certificates.X509Certificate2Collection$cert.Import([system.IO.File]::ReadAllBytes($file.FullName))}default{Write-Warning"Looks like your specified file is not a certificate file";return}}$cert|%{$status=$chain.Build($_)_getstatus_$status$chain$_}$cert.Reset()$chain.Reset()}}}}}

Данный скрипт может принимать аргументы в виде уже готовых объектов X509Certificate2 или с указанием пути к файлу сертификата, например:

dircert:currentusermy|Test-CertificateTest-Certificate.mycert.cer

Ну и при желании можно поуказывать там разные параметры и флаги проверки.

Про сертификаты:  Срок действия сертификата ЕГЭ увеличен до 4-х лёт

Powershell и аудит безопасности

Приветствую хабранарод! Хочу поделится с вами способом, который может облегчить рутинные будни системного администрирования Win системы, с помощью PowerShell. В один прекрасный день передо мной встала задача повседневного отслеживания активности пользователей, которые используют сервер терминалов в качестве рабочих станций.

Думаю я выражу не только свое мнение, сказав что «Просмотр событий» входящий в состав средств администрирования Windows, является не самым удобным средством отслеживания ситуации на сервере. Да там есть фильтр, по которому можно отсеивать только интересующие нас события, но нет удобного способа который меняет формат отображения данной информации. В результате чего и появилась идея с помощью PowerShell осуществлять парсинг событий журнала безопасности.

Для получения списка событий нам понадобится команда Get-EventLog одним из параметров которой является название журнала, в нашем случае security.

Команда отображает содержимое всего журнала, что в корне меня не устраивает. Но все не так плохо, то что вы видите на скриншоте, не просто текст, а вполне себе объекты, со свойствами которых можно делать все что угодно в рамках возможностей PowerShell.

Зная список свойств, можно манипулировать результатами работы Get-EventLog. Например что бы получить список всех событий за сегодняшний день, самым простым способом будет использование параметров командлета Get-EventLog, а именно параметр -after.

Полный список параметров можно узнать здесь. В результате у нас получится команда Get-EventLog security -after (Get-date -hour 0 -minute 0 -second 0), где командлет Get-Date выдает текущую дату и время, но параметры hour, minute и second задают вывод времени с начала текущего дня.

В результате мы получим список событий произошедших за сегодня. Уже лучше, но все еще не то. Мне необходимо получить список всех пользователей совершавших вход на сервер по протоколу RPD, что привело меня к изучению значений EventID и EntryType.

Значения entrytype

Данная информация почерпнута в основном из этого источника. Из полученных сведений можно сделать вывод что нам необходимо событие с EventID = 528 и EntryType = 10, что и будет соответствовать входу на компьютер через RDP. Немного изменим нашу команду.

Параметр -message отражает полностью сообщение нашего события, в котором содержится «Entry type» («Тип входа», так как у меня стоит русская версия 2003го), через шаблоны мы задаем поиск интересующей нас строки.

Про сертификаты:  Как установить сертификат в реестр через КриптоПРО | Настройка серверов windows и linux

Поскольку я не нашел в параметрах командлета Get_EventLog -EventID, то пришлось использовать возможности свойств объекта: $_ означает сам объект который фигурирует изначально-eq означает равенство значению, в нашем случае 528

Результатом выполнения будет следующее:

В общем, то, что нужно, но только вот выводится нам совсем не та информация. Будем исправлять. Для меня актуальными являются три параметра объекта, это: время, имя пользователя, IP адрес. В дальнейшем создадим объект, и занесем в него интересующие нас данные. Я создал скрипт “test.ps1”, т.к. команду целиком будет проблематично набирать.

$Events = Get-EventLog security -message “*Тип входа:?10*” -after (get-date -hour 0 -minute 0 -second 0) | ?{$_.eventid -eq 528 }

Значения eventid


Каждое событие входа в систему дополняется конкретным типом входа, список которых будет перечислен ниже.

  • 528 — Успешный вход пользователя на компьютер.
  • 529 — Отказ входа в систему. Не правильное имя пользователя или пароль.
  • 530 — Отказ входа в систему. Попытка входа в систему с учетной записью пользователя вне допустимого интервала времени.
  • 531 — Отказ входа в систему. Попытка входа в систему с использованием отключенной учетной записи пользователя.
  • 532 — Отказ входа в систему. Попытка входа в систему с использованием устаревшей учетной записи пользователя.
  • 533 — Отказ входа в систему. Попытка входа в систему пользователя, которому не разрешен вход на данный компьютер.
  • 534 — Отказ входа в систему. Попытка входа в систему с указанием неразрешенного типа входа.
  • 535 — Отказ входа в систему. Срок действия пароля для указанной учетной записи истек.
  • 536 — Отказ входа в систему. Служба Net Logon отключена.
  • 537 — Отказ входа в систему. Попытка входа в систему не удалась по другим причинам (В некоторых случаях причина отказа входа в систему может быть неизвестна).
  • 538 — Процесс выхода пользователя из системы завершен.
  • 539 — Отказ входа в систему. Во время попытки входа в систему учетная запись пользователя заблокирована.
  • 540 — Успешный вход пользователя в сеть.
  • 541 -Завершен основной режим проверки подлинности по протоколу IKE между локальным компьютером и зарегистрированной одноранговой тождественностью (установление надежного сопоставления), или быстрый режим установил канал данных.
  • 542 — Канал данных отключен.
  • 543 — Основной режим отключен.(Причиной этого может быть окончание временного интервала, ограничивающего длительность надежного соединения (по умолчанию — 8 часов), изменение политики или одноранговое завершение).
  • 544 — Отказ основного режима проверки подлинности из-за того, что партнер не обеспечил действительный сертификат или не подтверждена подлинность подписи.
  • 545 — Отказ основного режима проверки подлинности из-за отказа Kerberos или неверного пароля.
  • 546 — Отказ создания надежного соединения IKE, вызванный поступлением от партнера неприемлемого предложения. Прием пакета, содержащего неверные данные.
  • 547 — Отказ во время процедуры установления соединения IKE.
  • 548 — Отказ входа в систему. Идентификатор надежности (SID), полученный от доверенного домена, не соответствует SID учетной записи домена для клиента.
  • 549 — Отказ входа в систему. Все идентификаторы надежности SID, соответствующие недоверенным пространствам имен, были отфильтрованы во время проверки подлинности в лесах.
  • 550 — Сообщение уведомления, которое может указывать на возможную атаку на службу.
  • 551 — Пользователь инициировал процесс выхода из системы.
  • 552 — Пользователь успешно вошел на компьютер, используя правильные учетные данные, несмотря на то что до этого уже вошел как другой пользователь.
  • 682 — Пользователь повторно подключен к отключенному сеансу терминального сервера.
  • 683 — Пользователь отключен от сеанса терминального сервера без выхода из системы (Это событие формируется, когда пользователь подключен к сеансу терминального сервера через сеть. Оно появляется на сервере терминалов).
Оцените статью
Мой сертификат
Добавить комментарий