2019-07-20 17:59:35 +02:00
####
2019-09-11 02:26:11 +02:00
### pfSense Certificate Viewer (without private key)
2019-09-11 02:38:41 +02:00
### Version 1.0.4
2019-07-20 17:59:35 +02:00
####
2019-09-11 02:38:41 +02:00
# Redefine the $cfg string variable to point to a valid unecrypted pfSense Configuration XML file.
# 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-11 02:26:11 +02:00
# This script will return the CA certificates, Server certificates, User certificates (used or not) and duplicated Serial Number Certificates
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 {
Param ( [ Parameter ( Mandatory = $true , Position = 0 ) ]
[ string ] $path )
[ string[] ] $text = Get-Content $path -Encoding UTF8
#Remove 1st and last lines
$text [ 1 . . ( $text . Count - 2 ) ]
}
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 ) ) ) {
Write-Host 'No openvpn installation found. openssl.exe is part of the openVPN installation. If you have another openssl.exe available path, you can redefine the $openSSL variable at line 81.' -BackgroundColor DarkRed
Exit ( 3 )
}
$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 {
Write-Host " Bad password. Process stoped. " -BackgroundColor DarkRed
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-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-07-21 17:53:58 +02:00
foreach ( $r in $fxml . pfsense . 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-07-21 17:53:58 +02:00
Add-Lista -lista ( [ ref ] $listaC ) -obj ( [ ref ] $fxml . pfsense . ca ) -fromCA $true
2019-07-20 17:59:35 +02:00
#Add user/server certificates to $listaC (WITHOUT private keys)
2019-07-21 17:53:58 +02:00
Add-Lista -lista ( [ ref ] $listaC ) -obj ( [ ref ] $fxml . pfsense . 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-11 02:38:41 +02:00
Remove-Variable fxml
2019-07-20 17:59:35 +02:00
#List of CA Certificates
Write-Output " `n CA Certificates "
$listaC | Where-Object { $_ . isCA } | Select sIssuer , SerialNumber , FriendlyName , DnsNameList , sSubject | Sort-Object -Property sIssuer , SerialNumber | ft
#List of Server Certificates
Write-Output " `n Server Certificates "
2019-07-21 14:08:28 +02:00
$listaC | Where-Object { $_ . isServer } | Select 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 " `n User Certificates "
2019-07-21 14:08:28 +02:00
$listaC | Where-Object { -not ( $_ . isCA -or $_ . isServer ) } | Select 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 " `n Duplicated Serial Numbers (per CA) "
2019-07-21 14:08:28 +02:00
$listaC | Select sIssuer , SerialNumber , FriendlyName , DnsNameList , sSubject , revokedOn | Group-Object -Property sIssuer , SerialNumber | Where-Object { $_ . Count -gt 1 } | Select -ExpandProperty Group | ft