Projects > SSL/TLS Validation Tool

Description

A small python script that uses built in modules to determine the validity of TLS host certificates, giving you a heads before and when they expire. This prevents costly outages and helps to preserve customer trust. Send a simple email or add a custom integration to alert you when you need to take action.

#Created by Brian Winning Jr. https://www.brianwinning.com/
#Script Name: SSL/TLS Validation Tool
#Description: The purpose of this script is to query a TLS host and determine the validity of its certificate. Catching certificates before they expire prevents costly IT outages and preserves customer trust.

import socket
import ssl
import datetime
import logging
import smtplib

mailserver = 'smtp.yourdomain.com'  #The FQDN of your mail server.
mailport = 25   #The port you connect to your mail server on.
mailsender = '[email protected]' #The email address where you wish to have received emails come from.
mailrecipient = '[email protected]'  #The email address where you wish to receive alerts generated by the script.


def tls_expiry_datetime(hostname, ports):
    ssl_date_fmt = r'%b %d %H:%M:%S %Y %Z'

    context = ssl.create_default_context()
    conn = context.wrap_socket(
        socket.socket(socket.AF_INET),
        server_hostname=hostname,
    )
    conn.settimeout(3.0)

    conn.connect((hostname, ports))
    ssl_info = conn.getpeercert()
    # parse the string from the certificate into a Python datetime object
    return datetime.datetime.strptime(ssl_info['notAfter'], ssl_date_fmt)

def tls_valid_time_remaining(hostname, ports):
    #Get the number of days left in a cert's lifetime.
    expires = tls_expiry_datetime(hostname, ports)
    logging.debug(
        "SSL cert for %s expires at %s",
        hostname, expires.isoformat()
    )
    return expires - datetime.datetime.utcnow()

def tls_expires_in(hostname, buffer_days=120):
    #Check if `hostname` SSL cert expires is within `buffer_days Raises `AlreadyExpired` if the cert is past due

    remaining = tls_valid_time_remaining(hostname, ports)

    # if the cert expires in less than two weeks, we should reissue it
    if remaining < datetime.timedelta(days=0):
        # cert has already expired - uhoh!
        raise AlreadyExpired("Cert expired %s days ago" % remaining.days)
    elif remaining < datetime.timedelta(days=buffer_days):
        # expires sooner than the buffer
        return True

    else:
        # everything is fine
        return False

#This is where you define all of the hosts you would like to check against. Define an IP or FQDN and the port the server is listening on.
tls_hosts_to_check = {
'brianwinning.com': 443,
'192.168.1.1': 443,
'expired.badssl.com': 443,
'example.com': 2083}

#Validation of returned dictionary keys and values
#print(tls_hosts_to_check.keys())
#print(tls_hosts_to_check.values())

for hosts, ports, in tls_hosts_to_check.items():
    try:    #starts a capture for error handling
        expirydatetime = tls_expiry_datetime(hosts, ports)
        expireson = tls_valid_time_remaining(hosts, ports)
        expiresin = tls_expires_in(hosts, )
        print('')
        print('-------------------------------------------------------------------------------')
        print('Checking the certificate for ' + hosts + ' on TLS port ' + str(ports))
        print('The TLS certificate for ' + hosts + ' expires on ' + format(expirydatetime) + ' which is in exactly ' + format(expireson) + ' days.')
        if expiresin == None:
            print ('Uh oh cert has expired!')
        elif expiresin == True:
            print('The cert expires in ' + format(expireson) + ' days. Renew ASAP!')
            #msg = 'Subject: {}\n\n{}'.format (str(hosts) + ' TLS certificate expires soon.', str(hosts) + ' TLS certificate expires on ' + format(expirydatetime) + ', which is in ' + format(expireson))
            #server = smtplib.SMTP(mailserver, mailport) #Specifies what server to use for sending the email message.
            #server.sendmail(mailsender, mailrecipient, msg) #Opens an smtp connection to the server and sends the message.
            #server.quit()   #Closes the SMTP connection
        else:
            print('The cert is still valid, no need to take any action.')
        print('') #Leave some breathing room between the loop de loop on the screen.

        #print(format(expirydatetime) + format(expireson) + format(expiresin))
        #print(expiresin)
    except ssl.SSLCertVerificationError:    #handles invalid certificates gracefully / takes action.
        print('-------------------------------------------------------------------------------')
        print(hosts + " TLS certificate could not be validated. This could be because it's issued from an untrusted certificate authority, self-signed, or expired.")
        #Enter actions here
    except socket.timeout:  #handles host timeouts gracefully
        print('-------------------------------------------------------------------------------')
        print(hosts + " failed because a connection could not be made to this host. Pleae validate FQDN or IP and port is correct.")

Features

  • - Utilizes builtin socket and ssl modules to establish a connection to TLS hosts and retrieve the certifice.
  • - Parses certificate for certificate expiry date and compares it to current datetime using the datetime module.
  • - Alerts on Expired and about to expire certificates.
  • - Allows for the use of custom ports for each host.

Download




Download Verification:
  • SHA-512: cdf0cffb1f312758122c4ce008d1ac6ebcd0175cf229fe6f76854fb8411d0035e159061d889b840f5b0d21c9ef6e9ab48dca47ebe1025635c35367cc9bf334f1
  • SHA-256: 0cf213c40055779a8467e0c75a7d17c788a973b08a606b4ba0f2c247254192b8
  • SHA1: 17e12bca913446e44b6052ec66f9dc8e266257a3
  • MD5: 35c9bc3f463582f9d40bd65db65e9018

  • Version 1.0: First public release, July 4th 2020.

Disclaimer

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.