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:

image

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:

image

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:

image

Main grid

Main grid reflects the grid in application view:

image

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:

image

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

image

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

image

and we can expand each redirect entry:

image

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
<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>SSL Certificate Verifier Report</title>
<...>

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.

2 Comments

  1. Avatar Georg on August 3, 2020 at 10:00 am

    I didn’t find a way to configure a proxy in the GUI. Is there a way?

    • Vadims Podāns Vadims Podāns on August 3, 2020 at 10:29 am

      Right-click on server entry and select Properties context menu

Leave a Comment





This site uses Akismet to reduce spam. Learn how your comment data is processed.