Webinar: PKI Insights - Best Practices for Improving your PKI Posture Management Program for your Digital Certificates and Encryption by PKI Solutions
Schedule a Demo
Blog July 31, 2020 Certificate Transparency, Certificate Validation, PowerShell

SSL Certificate Verifier Tool v1.5.4 update

by Vadims Podāns

Hello everyone!

This week, we help a “Validating SSL Certificates the Easy Way” webinar where we talked about common SSL/TLS and displayed our free and open source SSL Certificate Verifier tool in action with new features.

Previous version of the tool was GUI-only and lacked exportable reports and any automation/scripting capabilities. I’ve addressed these limitations and presented during webinar. Today we have published new version on our website for download. In this post, I will outline new features we have added in new version.

Certificate Transparency Log search

In new version, we’ve added an optional check for TLS certificate publication in certificate transparency (CT) logs:

For CT log lookup we are using REST API provided by crt.sh certificate search service. When this setting is checked and we are unable to find presented TLS certificate in CT logs, a red flag is set for TLS server entry.

Exportable HTML Report

It is important to have exportable report capabilities for further review or responsible personnel about issues with TLS certificates on web servers. At any time, you can export current application state to HTML report by pressing a button on toolbar:

You will be prompted to specify destination location to save report. Report consists of three parts:

Scan settings
We replicate application settings used to perform scanning:

Main grid
Main grid reflects the grid in application view:

Certificate Details

In certificate details section, we show detailed certificates information for every TLS endpoint and every possible redirect within connection. This section represents a verbose output of Certificates tab in App UI:


Certificate Details section contains individual entries for every TLS server entry from main grid:

by expanding entry, we will see chains for every redirect:


and we can expand each redirect entry:

We see each chain certificate for that specific redirect, its details and certificate itself in PEM. If necessary, you can copy this PEM and save into .CER file. And you will see all reported errors associated with every certificate.

Scripting and automation

And the last notable piece we brought into new version – scripting and automation capabilities. I simply moved all core functionality into separate .NET class library (SSLVerifier.Core.dll) and added some POCO classes for easier access. You can use this library in your own .NET projects or use API directly in Windows PowerShell. Library uses .NET Standard compatible APIs, so you can get sources from GitHub and re-target the project to .NET Standard or .NET Core if necessary.

Automation in PowerShell is quite simple, you will need only few classes to make it working:

  • SSLVerifier.Core.Default.ServerEntry – represents TLS server endpoint object. As parameter accepts endpoint name and optional TLS port (if not specified, 443 is used by default)
  • SSLVerifier.Core.Default.CertProcessorConfig – represents scanner config object where you can configure processing rules. No parameters.
  • SSLVerifier.Core.Processor.CertProcessor – represents scanning engine. As parameter accepts scanner config object.
  • SSLVerifier.Core.Data.HtmlProcessor – represents HTML report builder. As parameter accepts scanner config object.

Let’s take a look into it:

PS C:\> # import DLL types to PowerShell session:
PS C:\> Add-Type -Path "C:\Program Files\PKI Solutions\SSL Verifier\SSLVerifier.Core.dll"
PS C:\> # create TLS server endpoint object. If we use port 443, we can omit last parameter
PS C:\> # I've added it for completeness.
PS C:\> $server = New-Object SSLVerifier.Core.Default.ServerEntry "google.lv", 443
PS C:\> $server

ServerAddress : google.lv
Port : 443
Proxy : SSLVerifier.Core.Default.ServerEntryProxy
ItemStatus : Unknown
Log : SSLVerifier.Core.Default.ServerLogWriter
SAN : {}
ChainStatus : NoError
Certificate :
Tree : {}

PS C:\>

We see server properties and several fields. You can provide proxy server information if necessary, but it’s not necessary for us right now. There are several properties scanner will fill during scanning: ItemStatus, SAN, ChainStatus, Certificate and Tree. Now, create scanner configuration:

PS C:\> $config = New-Object SSLVerifier.Core.Default.CertProcessorConfig
PS C:\> $config

AllowUserTrust : False
StrictUsage : False
WeakAlgorithms : {md2RSA, md4RSA, md5RSA, sha1RSA}
CheckWeakPubKey : True
MinimumRsaPubKeyLength : 2048
SslProtocolsToUse : Tls11, Tls12
Threshold : 30
SearchCT : False

PS C:\> $config.SearchCT = $true
PS C:\> $config.Threshold = 60 # set expiration warning to 60 days
PS C:\> # create scanner
PS C:\> $scanner = New-Object SSLVerifier.Core.Processor.CertProcessor $config
PS C:\>

Now, we are ready to fire scan:

PS C:\> $scanner.StartScan($server)
PS C:\> $server

ServerAddress : google.lv
Port : 443
Proxy : SSLVerifier.Core.Default.ServerEntryProxy
ItemStatus : Pending
Log : SSLVerifier.Core.Default.ServerLogWriter
SAN : {DNS Name=*.google.lv, DNS Name=*.google.com.lv, DNS Name=google.com.lv, DNS Name=google.lv...}
ChainStatus : NoError
Certificate : [Subject]
CN=*.google.lv, O=Google LLC, L=Mountain View, S=California, C=US

[Issuer]
CN=GTS CA 1O1, O=Google Trust Services, C=US

[Serial Number]
0096E49317B4886A040200000000726DC1

[Not Before]
2020.07.07. 11:14:00

[Not After]
2020.09.29. 11:14:00

[Thumbprint]
7F31CB3D7A6C4A28D2D5A7F96E7709C44D43CC97

Tree : {SSLVerifier.Core.Models.TreeNode`1[SSLVerifier.Core.IChainElement], SSLVerifier.Core.Models.TreeNode`1
[SSLVerifier.Core.IChainElement]}

PS C:\>

$scanner.StartScan method will take several seconds to complete. This method returns nothing, instead, it will fill properties for server object. We see that ItemStatus is now Pending, which means warning status for entry. Warning status is issued to about to expire TLS certificates, weak RSA keys and weak certificate signature algorithm. ChainStatus reports no error, so there are no notable chain issues. SAN stores a list of alternative names in TLS certificate. Certificate property is filled with TLS certificate. And Tree property contains certificate chain as tree. We can convert this tree to flat array by calling Flatten() method:

PS C:\> $server.Tree.Flatten()

<...>
Name                  : *.google.lv
Certificate           : [Subject]
                          CN=*.google.lv, O=Google LLC, L=Mountain View, S=California, C=US

                        [Issuer]
                          CN=GTS CA 1O1, O=Google Trust Services, C=US

                        [Serial Number]
                          0096E49317B4886A040200000000726DC1

                        [Not Before]
                          2020.07.07. 11:14:00

                        [Not After]
                          2020.09.29. 11:14:00

                        [Thumbprint]
                          7F31CB3D7A6C4A28D2D5A7F96E7709C44D43CC97

Parent                :
NativeErrorString     : AboutExpire
PropagatedErrorString : NoError
Child                 : {}
IsRoot                : False
HasErrors             : False
HasWarnings           : True
NativeErrors          : AboutExpire
PropagatedErrors      : NoError



PS C:\>

The method returns a flat array with chain elements from root down to end entity TLS certificate. I’ve stripped top-level chain elements for brevity and showing only leaf node which represents TLS certificate node. We have several automatic properties, such a HasErrors and HasWarnings. If any of these properties is not set to True, then we found issues with particular certificate. And we see that NativeErrors property is set to AboutExpire. Indeed, our expiration threshold was set to 60 days and in a given case certificate will expire in 59 days. What is the difference between NativeErrors and PropagatedErrors? Former contains errors associated with the current certificate node. Later contains errors propagated from upper level certificates in the chain. For example, untrusted root error will propagate down to all certificates under that specific root. For example:

PS C:\> $server = New-Object SSLVerifier.Core.Default.ServerEntry "untrusted-root.badssl.com"
PS C:\> $scanner.StartScan($server)
PS C:\> $server.Tree.Flatten()[-1]

Name : *.badssl.com
Certificate : [Subject]
CN=*.badssl.com, O=BadSSL, L=San Francisco, S=California, C=US

[Issuer]
CN=BadSSL Untrusted Root Certificate Authority, O=BadSSL, L=San Francisco, S=California, C=US

[Serial Number]
00ECB00B04F4E12D3C

[Not Before]
2019.10.10. 2:08:50

[Not After]
2021.10.09. 2:08:50

[Thumbprint]
69D6DC42A2D60A20CF2B384D3A7763EDABC2E144

Parent :
NativeErrorString : UntrustedRoot, RevocationStatusUnknown, OfflineRevocation, NotInTransparencyLog
PropagatedErrorString : UntrustedRoot
Child : {}
IsRoot : False
HasErrors : True
HasWarnings : False
NativeErrors : UntrustedRoot, RevocationStatusUnknown, OfflineRevocation, NotInTransparencyLog
PropagatedErrors : UntrustedRoot

PS C:\>

You can see that UntrustedRoot error is propagated down to all certificates under that root. So we know that not only leaf certificate has issues, but other certificates in the chain have issues too.

We can create HTML report from PowerShell too:

PS C:\> $htmlBuilder = New-Object SSLVerifier.Core.Data.HtmlProcessor $config
PS C:\> $htmlReport = $htmlBuilder.GenerateReport($server)
PS C:\> $htmlReport
 

You can save this HTML to a file or send via email, for example.

To summarize automation options, here a sample script that can be added to task scheduler for periodic scans:

Add-Type -Path "C:\Program Files\PKI Solutions\SSL Verifier\SSLVerifier.Core.dll"
$config = New-Object SSLVerifier.Core.Default.CertProcessorConfig
$config.SearchCT = $true
$config.Threshold = 60
$scanner = New-Object SSLVerifier.Core.Processor.CertProcessor $config
$htmlBuilder = New-Object SSLVerifier.Core.Data.HtmlProcessor $config
$serverList = "web1.example.com","web2.example.com","webX.example.com" | %{
    $server = New-Object SSLVerifier.Core.Default.ServerEntry $_
    $scanner.StartScan($server)
    if ($server.ItemStatus -ne "Valid") {
        # server scan failed, take appropriate actions. In this case, we start with
        # HTML report generation for further analysis
        $html = $htmlBuilder.GenerateReport($server)
        # send this HTML as attachment via email, or save it to reports folder, or add
        # your own logic here.
    }
}

I hope you find these features useful for you.

Related Resources

  • Blog
    July 6, 2021

    Register TLS certificate with Remote Desktop Service using PowerShell

    Certificates, PowerShell, RDP
  • Blog
    May 7, 2021

    Just Released – Licensing Options for Our PKI Tools

    Development, PKI, PowerShell, Products, PSFCIV, PSPKI
  • Blog
    March 29, 2021

    PowerShell File Checksum Integrity Verifier (PsFCIV)

    PowerShell, PSFCIV

Vadims Podāns

PKI Software Architect

View All Posts by Vadims Podāns

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *