Shell script to check SSL certificate info like expiration date and subject

Remembering the correct openssl syntax for fetching certificate from a remote host or parsing a local certificate file for useful information is a chore, so I finally took my notes and combined into an easy to use shell script.

The script is mostly useful for not having to remember cryptic syntax, but in some cases will also parse and present information in a more readable format than the default openssl output.

It's also easy to add parsing and formatting as needed.

For example, to get certificate expiration date from a remote host, you would normally have to remember a command like:

$ echo | openssl s_client -connect 2>/dev/null | openssl x509 -noout -enddate

And for your trouble, would be rewarded with output like this:

notAfter=Jun 10 00:00:00 2014 GMT

With my little script, you'd only have to type:

$ ssl-cert-info --host --end

And get back output in your own timezone:

2014-06-09 17:00:00 PDT

However, if you really want to see raw output from openssl, you could pass any openssl option through to it like so (the option passed through in this case is '-dates'):

$ ssl-cert-info --host --option -dates

And get back output like this:

notBefore=Mar 12 09:48:29 2014 GMT
notAfter=Jun 10 00:00:00 2014 GMT

Though I find the following much easier to understand:

$ ssl-cert-info --host --dates
valid from: 2014-03-12 02:48:29 PDT
valid till: 2014-06-09 17:00:00 PDT

And here's the script:

cat <<EOF
Usage: $(basename $0) [options]
This shell script is a simple wrapper around the openssl binary. It uses
s_client to get certificate information from remote hosts, or x509 for local
certificate files. It can parse out some of the openssl output or just dump all
of it as text.
  --all-info   Print all output, including boring things like Modulus and 
  --alt        Print Subject Alternative Names. These will be typically be 
               additional hostnames that the certificate is valid for.
  --cn         Print commonName from Subject. This is typically the host for 
               which the certificate was issued.
  --debug      Print additional info that might be helpful when debugging this
  --end        Print certificate expiration date. For additional functionality
               related to certificate expiration, take a look at this script:
  --dates      Print start and end dates of when the certificate is valid.
  --file       Use a local certificate file for input.
  --help       Print this help message.
  --host       Fetch the certificate from this remote host.
  --name       Specify a specific domain name (Virtual Host) along with the
               request. This value will be used as the '-servername' in the 
               s_client command. This is for TLS SNI (Server Name Indication).
  --issuer     Print the certificate issuer.
  --most-info  Print almost everything. Skip boring things like Modulus and
  --option     Pass any openssl option through to openssl to get its raw
  --port       Use this port when conneting to remote host. If ommitted, port
               defaults to 443.
  --subject    Print the certificate Subject -- typically address and org name.
  1. Print a list of all hostnames that the certificate used by 
     is valid for.
     $(basename $0) --host --alt
  2. Print issuer of certificate used by Fetch certficate info
     over port 465.
     $(basename $0) --host --port 465 --issuer
         countryName               = US
         organizationName          = Google Inc
         commonName                = Google Internet Authority G2
  3. Print valid dates for the certificate, using a local file as the source of 
     certificate data. Dates are formatted using the date command and display
     time in your local timezone instead of GMT.
     $(basename $0) --file /path/to/file.crt --dates
     valid from: 2014-02-04 16:00:00 PST
     valid till: 2017-02-04 15:59:59 PST
  4. Print certificate serial number. This script doesn't have a special option
     to parse out the serial number, so will use the generic --option flag to
     pass '-serial' through to openssl.
     $(basename $0) --host --option -serial
if ! [ -x "$(type -P openssl)" ]; then
  echo "ERROR: script requires openssl"
  echo "For Debian and friends, get it with 'apt-get install openssl'"
  exit 1
while [ "$1" ]; do
  case "$1" in
            servername="-servername $1"
            FormatOutput() { 
              grep -A1 "Subject Alternative Name:" | tail -n1 |
              tr -d ' ' | tr ',' '\n'
            opt="-subject -nameopt multiline"
            FormatOutput() { 
              awk '/commonName/ {print$NF}'
            FormatOutput() { 
              dates=$(cat -)
              start=$(grep Before <<<"$dates" | cut -d= -f2-)
              end=$(grep After <<<"$dates" | cut -d= -f2-)
              echo valid from: $(date -d "$start" '+%F %T %Z')
              echo valid till: $(date -d "$end" '+%F %T %Z')
            FormatOutput() { 
              read end
              end=$(cut -d= -f2- <<<"$end")
              date -d "$end" '+%F %T %Z'
            opt="-issuer -nameopt multiline"
            opt="-text -certopt no_header,no_version,no_serial,no_signame,no_pubkey,no_sigdump,no_aux"
            opt="-subject -nameopt multiline"
            exit 0
            echo "$(basename $0): invalid option $1" >&2
            echo "see --help for usage"
            exit 1
  openssl x509 -in $crt -noout $opt
  echo |
  openssl s_client $servername -connect $host:$port 2>/dev/null |
  openssl x509 -noout $opt
if [ -z "$(type -t FormatOutput)" ]; then
  FormatOutput() { cat; }
if [ -z "$opt" ]; then
  opt="-text -certopt no_header,no_version,no_serial,no_signame,no_pubkey,no_sigdump,no_aux"
if [ -z "$source" ]; then
  echo "ERROR: missing certificate source."
  echo "Provide one via '--file' or '--host' arguments."
  echo "See '--help' for examples." 
  exit 1
if [ "$source" == "local" ]; then
  [ -n "$DEBUG" ] && echo "DEBUG: certificate source is local file"
  if [ -z "$crt" ]; then
    echo "ERROR: missing certificate file"
    exit 1
  [ -n "$DEBUG" ] && echo
  CheckLocalCert | FormatOutput
if [ "$source" == "remote" ]; then
  [ -n "$DEBUG" ] && echo "DEBUG: certificate source is remote host"
  if [ -z "$host" ]; then
    echo "ERROR: missing remote host value."
    echo "Provide one via '--host' argument"
    exit 1
  if [ -z "$port" ]; then
    [ -n "$DEBUG" ] && echo "DEBUG: defaulting to 443 for port."
  [ -n "$DEBUG" ] && echo
  CheckRemoteCert | FormatOutput


  • 1. n2 replies at 24th April 2014, 6:58 am :

    Thanks for the script! Will come real handy and beats having to memorise or alias openssl s_client -connect host:443 2>/dev/null | openssl x509 -noout -text

  • 2. luke replies at 13th August 2014, 6:59 am :


  • 3. Indranil Das Gupta replies at 30th August 2014, 12:29 am :

    Hi Alain,

    I would like to use this bash script in one of my projects (which is incidentally on GPLv2+ licensing).

    How may I consider your script to be licensed as – Public Domain, BSD,
    MIT, GPLv2+ or AGPL?

    thanks in advance.

  • 4. Alain Kelder replies at 30th August 2014, 4:51 pm :

    Hi Indra,

    Everything on this blog is CC BY 3.0 US:


  • 5. Thomas replies at 15th February 2016, 4:56 am :

    Hi Alain.

    Thank you so much for this script. I found a small issue though :)
    Can you change the call to s_client so that it supports sni? I found how to do it here:

    I guess what need to be changed is this:

      echo | openssl s_client -servername $host -connect $host:$port 2>/dev/null | openssl x509 -noout $opt
  • 6. Alain Kelder replies at 20th February 2016, 11:34 pm :

    Thomas, thanks for the tip! I’ve updated the script.

  • 7. Sathiya replies at 27th February 2016, 11:41 pm :

    Hi Alain ,

    Thanks for the good script. We have checked this script for RHEL5 with –host option with server name it’s works .However when we try with –host local it’s thrown the below error.


    It’s thrown the same error for RHEL 6 in both the option
    RHEL 6 Error local or remote :

    unable to load certificate
    139717751199560:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:703:Expecting: TRUSTED CERTIFICATE

    RHEL 5 error with local options

    24480:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:647:Expecting: TRUSTED CERTIFICATE

    Pls let me know what’s wrong here …

  • 8. Alain Kelder replies at 4th June 2016, 9:28 am :

    Sathiya, the error “unable to load certificate”, means just that — openssl wasn’t able to access the certificate as provided. Did you actually run the script with “–host local” option? That will cause the script to try contact a host named “local” to fetch the certificate. Unless you actually have a host named “local” on your network, that will fail with the error that you got.

    If you want to check a local file, instead of “–host local”, try “–file /path/to/your/certificate/file”.

Leave a comment

NOTE: Enclose quotes in <blockquote></blockquote>. Enclose code in <pre lang="LANG"></pre> (where LANG is one of these).