Загрузка данных


<#
.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
}