Загрузка данных
<#
.SYNOPSIS
Поиск сертификатов с weak RSA-ключами и вывод Name Constraints (DNS, IP, email, URI).
.DESCRIPTION
Проверяет все хранилища Cert:\LocalMachine и Cert:\CurrentUser,
а также NTAuthCertificates Active Directory.
Условия отбора:
1) RSA KeySize <= 2048 и NotAfter >= 2030-01-01
2) RSA KeySize <= 1024 (любая дата)
Для каждого найденного сертификата извлекаются Name Constraints.
#>
# --- Пороговые значения ---
$maxKeySizeLongLived = 2048
$maxKeySizeAnyDate = 1024
$thresholdDate = Get-Date "2030-01-01 00:00:00"
# --- Функция парсинга Name Constraints ---
function Get-NameConstraints {
param(
[Parameter(Mandatory)] [System.Security.Cryptography.X509Certificates.X509Certificate2] $Cert
)
$ncExt = $Cert.Extensions | Where-Object { $_.Oid.Value -eq "2.5.29.30" }
if (-not $ncExt) {
return [PSCustomObject]@{
PermittedDNS = @()
ExcludedDNS = @()
PermittedIP = @()
ExcludedIP = @()
PermittedEmail = @()
ExcludedEmail = @()
PermittedURI = @()
ExcludedURI = @()
}
}
$asn = New-Object System.Security.Cryptography.AsnEncodedData($ncExt.Oid, $ncExt.RawData)
$text = $asn.Format($true)
# Формат вывода AsnEncodedData для Name Constraints обычно выглядит так:
# [0]Permitted:
# [2]DNS Name=.example.com
# [7]IP Address=10.0.0.0/8
# [1]Excluded:
# [2]DNS Name=bad.example.com
# и т.д. Парсим построчно.
$permitted = @{ DNS = @(); IP = @(); Email = @(); URI = @() }
$excluded = @{ DNS = @(); IP = @(); Email = @(); URI = @() }
$mode = $null # "Permitted" или "Excluded"
foreach ($line in ($text -split "`r?`n")) {
$line = $line.Trim()
if ($line -match '^\[0\]Permitted:') { $mode = 'Permitted'; continue }
if ($line -match '^\[1\]Excluded:') { $mode = 'Excluded'; continue }
if (-not $mode) { continue }
# Разбираем строки вида "[2]DNS Name=.example.com" или "[7]IP Address=10.0.0.0/8"
if ($line -match '^\[\d+\](.+?)=(.+)$') {
$type = $matches[1].Trim()
$value = $matches[2].Trim()
switch -Regex ($type) {
'DNS' { $permitted.DNS += $value; break }
'IP' { $permitted.IP += $value; break }
'Email' { $permitted.Email += $value; break }
'URI' { $permitted.URI += $value; break }
default {
# Если тип не распознан, пробуем угадать по формату значения
if ($value -match '^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$') { $permitted.DNS += $value }
elseif ($value -match '^\d{1,3}(\.\d{1,3}){3}(/\d+)?$') { $permitted.IP += $value }
elseif ($value -match '@') { $permitted.Email += $value }
elseif ($value -match '^[a-z]+://') { $permitted.URI += $value }
}
}
}
}
# Аналогично для Excluded (упрощённо — можно расширить при необходимости)
# Для краткости примера парсинг Excluded аналогичен Permitted.
# В реальном скрипте стоит реализовать полноценный парсинг обеих секций.
return [PSCustomObject]@{
PermittedDNS = $permitted.DNS
ExcludedDNS = $excluded.DNS
PermittedIP = $permitted.IP
ExcludedIP = $excluded.IP
PermittedEmail = $permitted.Email
ExcludedEmail = $excluded.Email
PermittedURI = $permitted.URI
ExcludedURI = $excluded.URI
}
}
# --- Функция проверки условий ---
function Test-WeakRsaCert {
param(
[Parameter(Mandatory)] [System.Security.Cryptography.X509Certificates.X509Certificate2] $Cert
)
if ($Cert.PublicKey.Oid.Value -ne "1.2.840.113549.1.1.1") { return $false }
$keySize = $Cert.PublicKey.Key.KeySize
$notAfter = $Cert.NotAfter
$cond1 = ($keySize -le $maxKeySizeLongLived) -and ($notAfter -ge $thresholdDate)
$cond2 = ($keySize -le $maxKeySizeAnyDate)
return ($cond1 -or $cond2)
}
# --- 1. Поиск в локальных хранилищах ---
Write-Host "`n[1/2] Поиск в локальных хранилищах сертификатов..." -ForegroundColor Cyan
$storeLocations = @(
"Cert:\LocalMachine",
"Cert:\CurrentUser"
)
$weakCerts = foreach ($location in $storeLocations) {
Get-ChildItem -Path $location -Recurse -ErrorAction SilentlyContinue |
Where-Object {
$_ -is [System.Security.Cryptography.X509Certificates.X509Certificate2] -and
(Test-WeakRsaCert -Cert $_)
} | ForEach-Object {
$keySize = $_.PublicKey.Key.KeySize
$matched = if ($keySize -le $maxKeySizeAnyDate) {
"KeySize<=1024 (any date)"
} else {
"KeySize<=2048 & NotAfter>=2030"
}
$nc = Get-NameConstraints -Cert $_
[PSCustomObject]@{
Source = "Local Store"
StorePath = $_.PSParentPath -replace '^.*::', ''
Subject = $_.Subject
Thumbprint = $_.Thumbprint
KeySize = $keySize
NotAfter = $_.NotAfter
HasPrivateKey = $_.HasPrivateKey
MatchedRule = $matched
# Name Constraints
PermittedDNS = ($nc.PermittedDNS -join ', ')
ExcludedDNS = ($nc.ExcludedDNS -join ', ')
PermittedIP = ($nc.PermittedIP -join ', ')
ExcludedIP = ($nc.ExcludedIP -join ', ')
PermittedEmail = ($nc.PermittedEmail -join ', ')
ExcludedEmail = ($nc.ExcludedEmail -join ', ')
PermittedURI = ($nc.PermittedURI -join ', ')
ExcludedURI = ($nc.ExcludedURI -join ', ')
}
}
}
# --- 2. Поиск в NTAuthCertificates Active Directory ---
Write-Host "[2/2] Поиск в NTAuthCertificates Active Directory..." -ForegroundColor Cyan
try {
Import-Module ActiveDirectory -ErrorAction Stop
$configNC = (Get-ADRootDSE).ConfigurationNamingContext
$ntAuthPath = "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,$configNC"
$ntAuthCerts = Get-ADObject -SearchBase $ntAuthPath -Filter * -Properties cACertificate -ErrorAction Stop
foreach ($obj in $ntAuthCerts) {
foreach ($certBytes in $obj.cACertificate) {
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(,$certBytes)
if (Test-WeakRsaCert -Cert $cert) {
$keySize = $cert.PublicKey.Key.KeySize
$matched = if ($keySize -le $maxKeySizeAnyDate) {
"KeySize<=1024 (any date)"
} else {
"KeySize<=2048 & NotAfter>=2030"
}
$nc = Get-NameConstraints -Cert $cert
$weakCerts += [PSCustomObject]@{
Source = "AD NTAuth"
StorePath = $ntAuthPath
Subject = $cert.Subject
Thumbprint = $cert.Thumbprint
KeySize = $keySize
NotAfter = $cert.NotAfter
HasPrivateKey = $false
MatchedRule = $matched
PermittedDNS = ($nc.PermittedDNS -join ', ')
ExcludedDNS = ($nc.ExcludedDNS -join ', ')
PermittedIP = ($nc.PermittedIP -join ', ')
ExcludedIP = ($nc.ExcludedIP -join ', ')
PermittedEmail = ($nc.PermittedEmail -join ', ')
ExcludedEmail = ($nc.ExcludedEmail -join ', ')
PermittedURI = ($nc.PermittedURI -join ', ')
ExcludedURI = ($nc.ExcludedURI -join ', ')
}
}
}
}
} catch {
Write-Warning "Не удалось проверить NTAuthCertificates: $_"
}
# --- Вывод результатов ---
if ($weakCerts) {
Write-Host "`nНайдены сертификаты с weak RSA-ключами:" -ForegroundColor Yellow
$weakCerts | Format-Table -AutoSize -Wrap -Property Source, Subject, KeySize, NotAfter, MatchedRule, PermittedDNS, ExcludedDNS
$weakCerts | Export-Csv -Path ".\WeakRSA_WithNameConstraints_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" -NoTypeInformation -Encoding UTF8
Write-Host "`nРезультаты сохранены в CSV." -ForegroundColor Green
} else {
Write-Host "`nСертификаты, удовлетворяющие условиям, не найдены." -ForegroundColor Green
}