pfSense-Certificate-Viewer/pfSenseCertViewer.ps1

223 lines
8.5 KiB
PowerShell
Raw Normal View History

2019-07-20 17:59:35 +02:00
####
2019-09-11 02:26:11 +02:00
### pfSense Certificate Viewer (without private key)
2019-09-13 02:41:18 +02:00
### Version 1.0.5
2019-07-20 17:59:35 +02:00
####
2019-09-13 18:47:27 +02:00
# Redefine the $cfg string variable to point to a valid pfSense Configuration XML file.
2019-09-11 02:38:41 +02:00
# You can also use the command line FilePath parameter as path to the input XML cfg file
2019-07-21 17:53:58 +02:00
2019-09-13 18:47:27 +02:00
# This script will return the CA certificates, Server certificates, User certificates (used or not)
# and duplicated Serial Number Certificates. If as result of errors generating serialnumber certificates,
# duplicated serialnumber certs (from the same CA) will be reported.
2019-07-20 17:59:35 +02:00
#
2019-09-11 02:26:11 +02:00
# Tested on PowerShell 5.0 and avobe
2019-07-20 17:59:35 +02:00
# Created by Alvaro Sedano Galindo. al_sedano@hotmail.com
2019-07-21 12:33:56 +02:00
#
2019-07-20 17:59:35 +02:00
2019-07-21 17:53:58 +02:00
#[CmdletBinding()]
Param (
[Parameter(Mandatory=$false,
2019-09-11 02:38:41 +02:00
Position=0,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
2019-07-21 17:53:58 +02:00
[Alias("File")]
[string]$FilePath)
2019-09-11 02:38:41 +02:00
Function Get-BeginEndWO {
2019-09-13 02:41:18 +02:00
Param([Parameter(Mandatory=$true, Position=0)][string]$path)
2019-09-11 02:38:41 +02:00
2019-09-13 17:53:06 +02:00
#OPNsense saves information on how to decrypt it in the xml encrypted file.
#pfSense does'nt.
2019-09-13 02:41:18 +02:00
#Check if "^Version: OPNsense" exists in the line 2
2019-09-11 02:38:41 +02:00
[string[]]$text = Get-Content $path -Encoding UTF8
2019-09-13 02:41:18 +02:00
if ($text[1] -match '^Version: OPNsense') {
[int]$start = 5
}
else {
[int]$start = 1
}
2019-09-11 02:38:41 +02:00
#Remove 1st and last lines
2019-09-13 02:41:18 +02:00
$text[$start..($text.Count-2)]
2019-09-11 02:38:41 +02:00
}
2019-07-20 17:59:35 +02:00
Function Get-CN {
Param([Parameter(Mandatory=$true)][string]$name)
if($name -match "CN=([^,]*)") {
$Matches[1] }
else {$name}
}
Function Add-Lista {
Param([Parameter(Mandatory=$true)][ref]$lista `
,[Parameter(Mandatory=$true)][ref]$obj `
,[Parameter(Mandatory=$true)][bool]$fromCA)
[string]$oidCLI = '1.3.6.1.5.5.7.3.2'
[string]$oidSRV = '1.3.6.1.5.5.7.3.1'
2019-07-21 12:33:56 +02:00
[array]$revs = $listaR | Select -ExpandProperty refid -Unique
2019-07-20 17:59:35 +02:00
[System.Security.Cryptography.X509Certificates.X509Certificate2]$ccc = $null
foreach($c in $obj.Value) {
$ccc = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new([System.Convert]::FromBase64String($c.crt))
2019-07-21 12:33:56 +02:00
$ccc.FriendlyName = $c.descr.'#cdata-section'
2019-07-21 14:08:28 +02:00
$objTmp = $ccc | Select *, @{N='IsCA';E={$fromCA}} `
2019-07-20 17:59:35 +02:00
, @{N='IsServer';E={-not $fromCA -and $_.EnhancedKeyUsageList.ObjectId -contains $oidSRV}} `
, @{N='IsClient';E={-not $fromCA -and $_.EnhancedKeyUsageList.ObjectId -contains $oidCLI}} `
2019-07-21 12:33:56 +02:00
, @{N='sIssuer';E={Get-CN($_.Issuer)}}, @{N='sSubject';E={Get-CN($_.Subject)}} `
, @{N='refid'; E={$c.refid}} `
2019-07-21 14:08:28 +02:00
, @{N='isRevoked'; E={-not $fromCA -and $c.refid -in $revs}} `
, @{N='revokedOn'; Expression={$null}} `
if ($objTmp.isRevoked) {
[string[]]$strRev = @()
foreach($d in $listaR) {
if ($d.refid -eq $c.refid) {
$strRev += [string]($d.listRev)
}
}
$objTmp.revokedOn = $strRev
}
$lista.Value += $objTmp
2019-07-20 17:59:35 +02:00
}
}
2019-09-11 02:38:41 +02:00
Function Decrypt {
Param([Parameter(Mandatory=$true,Position=0)][string]$fileIn
,[Parameter(Mandatory=$true,Position=1)][string]$fileOut
,[Parameter(Mandatory=$false,Position=2)][string]$pass)
# If $openSSL is not '', we will look for the openSSL.exe available with openVPN install.
# You can define a value for $openSSL if you have a valid openssl executable path.
[string]$openSSL = ''
if ($openSSL -eq '') {
#Look for openvpn installation
[string]$rutaREG = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\OpenVPN"
if (-not (Test-Path($rutaREG))) {
2019-09-13 02:41:18 +02:00
Write-Host 'No openvpn installation found. openssl.exe is part of the openVPN installation. ' + `
2019-09-13 18:47:27 +02:00
'If you have another openssl.exe available path, you can redefine the $openSSL variable at line 92.' -BackgroundColor DarkRed
2019-09-13 02:41:18 +02:00
Exit 3
2019-09-11 02:38:41 +02:00
}
$openSSL = ((Get-ItemProperty -Path $rutaREG).exe_path).Replace("openvpn.exe", "openssl.exe")
}
if ($pass -eq '') {
[System.Security.SecureString]$pwd = Read-Host "Password XML File:" -AsSecureString
$pass = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwd))
}
& "$($openSSL)" enc -d -aes-256-cbc -in "$($fileIn)" -out "$($fileOut)" -salt -md md5 -k ''$($pass)''
}
Function Get-ConfigFile {
Param([Parameter(Mandatory=$true,Position=0)][string]$filePath `
,[Parameter(Mandatory=$true,Position=1)][ref]$xml)
if (-not (Test-Path -Path $filePath)) {
Write-Host "File '$cfg' not found. Process stopped." -BackgroundColor DarkRed
Exit 1
}
[bool]$encrypted = $false
try {
$xml.Value = Get-Content $filePath -Encoding UTF8
}
catch {
$encrypted = $true
}
if ($encrypted -eq $true) {
#Encrypted xml file
[string[]]$cifrado = Get-BeginEndWO -path $filePath
$f1Cin = New-TemporaryFile
$f1Cou = New-TemporaryFile
try {
[IO.File]::WriteAllBytes($f1Cin.FullName, [System.Convert]::FromBase64String($cifrado))
Decrypt -fileIn $f1Cin.FullName -fileOut $f1Cou.FullName
# Check if file exists
if (-not (Test-Path $f1Cou.FullName) -or (Get-Item $f1Cou.FullName).Length -eq 0) {
Write-Host "Unable to decrypt file. Process stoped." -BackgroundColor DarkRed
Exit 4
}
# File exists
$xml.Value = Get-Content $f1Cou.FullName -Encoding UTF8
}
catch {
2019-09-13 02:41:18 +02:00
Write-Host "Error decrypting xml file: Bad password. Process stoped." -BackgroundColor DarkRed
2019-09-11 02:38:41 +02:00
Exit 5
}
finally {
Remove-Item $f1Cin.FullName -Force
Remove-Item $f1Cou.FullName -Force
}
}
}
2019-07-20 17:59:35 +02:00
#
# BODY
#
2019-09-11 02:38:41 +02:00
#$ErrorActionPreference = 'SilentlyContinue'
2019-07-21 17:53:58 +02:00
# Check if param 0 is assigned
if ($FilePath -eq $null -or $FilePath -eq '') {
[string]$cfg = "$env:USERPROFILE\Downloads\config-pfSense01.private.xml"
}
else {
# Use the FilePath console input parameter
[string]$cfg = $FilePath
}
2019-09-11 02:38:41 +02:00
#Read XML pfSense config file (UTF8 Encoding)
[xml]$fxml = $null
Get-ConfigFile -filePath $cfg -xml ([ref]$fxml)
2019-07-20 17:59:35 +02:00
2019-09-13 02:41:18 +02:00
#Check for pfSense/OPNsense products
if ($fxml.ChildNodes.Count -eq 2) {
[System.Xml.XmlElement]$product = $fxml.ChildNodes[1]
if ($product.Name -notin ('pfsense','opnsense')) {
Write-Host 'The xml file does not contains a pfSense or OPNsense backup. Process stoped.' -BackgroundColor DarkRed
Exit 6
}
}
Remove-Variable fxml
2019-07-21 12:33:56 +02:00
#Get the CRL revocation list
2019-07-21 14:08:28 +02:00
[DateTime]$time0 = '1970-01-01'
2019-07-21 12:33:56 +02:00
[array]$listaR = @()
2019-09-13 02:41:18 +02:00
foreach($r in $product.crl) {
2019-07-21 14:08:28 +02:00
$listaR += $r.cert | Select @{N='listRev';E={$r.descr.'#cdata-section'}}, caref, refid, reason, @{N='revDate';E={$time0.AddSeconds($_.revoke_time)}}
2019-07-21 12:33:56 +02:00
}
2019-07-20 17:59:35 +02:00
#Add CA Certificates to $listaC (WITHOUT private keys)
[array]$listaC = @()
2019-09-13 02:41:18 +02:00
Add-Lista -lista ([ref]$listaC) -obj ([ref]$product.ca) -fromCA $true
2019-07-20 17:59:35 +02:00
#Add user/server certificates to $listaC (WITHOUT private keys)
2019-09-13 02:41:18 +02:00
Add-Lista -lista ([ref]$listaC) -obj ([ref]$product.cert) -fromCA $false
2019-09-11 02:26:11 +02:00
#Note: User Certificates created with old pfSense versions could set the EnhancedKeyUsageList property to <empty>.
2019-07-20 17:59:35 +02:00
2019-09-13 02:54:33 +02:00
Remove-Variable product
2019-07-20 17:59:35 +02:00
#List of CA Certificates
Write-Output "`nCA Certificates"
2019-09-13 17:53:06 +02:00
$listaC | Where-Object {$_.isCA} | Select-Object sIssuer, SerialNumber, FriendlyName, DnsNameList, sSubject | Sort-Object -Property sIssuer, SerialNumber | ft
2019-07-20 17:59:35 +02:00
#List of Server Certificates
Write-Output "`nServer Certificates"
2019-09-13 17:53:06 +02:00
$listaC | Where-Object {$_.isServer} | Select-Object sIssuer, SerialNumber, FriendlyName, DnsNameList, sSubject, revokedOn | Sort-Object -Property sIssuer, SerialNumber | ft
2019-07-20 17:59:35 +02:00
#List of User Certificates (not CA and not Server)
Write-Output "`nUser Certificates"
2019-09-13 17:53:06 +02:00
$listaC | Where-Object {-not ($_.isCA -or $_.isServer)} | Select-Object sIssuer, SerialNumber, FriendlyName, DnsNameList, sSubject, revokedOn | Sort-Object -Property sIssuer, SerialNumber | ft
2019-07-20 17:59:35 +02:00
#List of Dupicated SerialNumbers (per CA)
Write-Output "`nDuplicated Serial Numbers (per CA)"
2019-09-13 17:53:06 +02:00
$listaC | Select-Object sIssuer, SerialNumber, FriendlyName, DnsNameList, sSubject, revokedOn | Group-Object -Property sIssuer, SerialNumber | Where-Object {$_.Count -gt 1} | Select -ExpandProperty Group | ft