check-cert: Go-based tooling to check/verify certs

check-cert

Go-based tooling to check/verify certs (e.g., as part of a Nagios service check)

Latest Release Go Reference Validate Codebase Validate Docs Lint and Build using Makefile Quick Validation

Table of Contents

Project home

See our GitHub repo for the latest code, to file an issue or submit improvements for review and potential inclusion into the project.

Overview

This repo contains various tools used to monitor/validate certificates.

Tool Name Status Description
check_certs Beta Nagios plugin used to monitor certificate chains.
lscert Beta Small CLI app used to generate a summary of certificate metadata and expiration status.
fixsn Alpha Small CLI app used to convert a given base 10 serial number to base 16, colon-delimited hex string format.
certsum Alpha CLI app used to scan one or more given CIDR IP ranges for certs and provide a summary report.

check_certs

Nagios plugin used to monitor certificate chains. In addition to the features shared with lscert, this app also validates the provided hostname against the certificate Common Name or one of the available SANs entries.

The output for this application is designed to provide the one-line summary needed by Nagios for quick identification of a problem while providing longer, more detailed information for use in email and Teams notifications (atc0005/send2teams).

lscert

Small CLI tool for quickly reviewing the results of replacing a certificate and/or troubleshoot why connections to a certificate-enabled service may be failing.

Certificate metadata can be retrieved from:

  • a remote service at a specified fully-qualified domain name (e.g., www.github.com) or IP Address and port (e.g., 443)
  • a local certificate "bundle" or standalone leaf certificate file

If specifying a host via IP Address, a warning will be emitted unless the IP Address is in the SANs list for the certificate. This warning can be ignored for the purposes of reviewing the cert details, Provide a valid FQDN as the server name or the "dns name" if you wish to apply hostname validation.

fixsn

A small CLI app used to convert a given (assumed) base 10 number into a base 16, colon delimited hex string representing a certificate serial number. Prior releases of this project improperly displayed serial numbers as base 10 values instead of base 16, colon delimited hex strings. Using this tool can be useful for one-off conversion of older values to the proper format (e.g., a certs list maintained in documentation).

It is likely that this tool will be either removed or folded into another tool at a future date, unless others find it useful.

certsum

certsum is an IP range cert scanner prototype. This tool is currently of "alpha" level quality; many of the exposed flags, help text and summary output are subject to change significantly in later releases.

This tool is intended for scanning one or more given IP ranges in order to generate a report for discovered certificates, but may be used to scan as few as one target.

Performance is likely to be acceptable as-is for smaller IP ranges, but may be adjusted as needed using the rate limit tuning flag (see the configuration options section for details). The current default value is an attempt to balance scanning speed against OS limitations on the number of open file handles. If adjusting this value, start with small increments to determine best results for your environment.

A default inactivity timeout is used to terminate the application if scanning attempts stall for a specified period of time. See the configuration options section for details.

IP Addresses may be specified as comma-separated values:

  • individual IP Addresses
  • CIDR IP ranges
  • partial ranges
    • using partial implementation of octet range addressing (e.g., 192.168.2.10-15)
  • Fully-qualified domain names (FQDNs)
  • Hostnames (fragile)
    • this is highly dependent on your DNS configuration, particularly any configured search list (aka, DNS Suffix Search List in Windows terminology) entries used to qualify short/hostname values

Support is present (though limited) for filtering "OK" status hosts and certs to either increase or reduce the amount of information provided in the generated summary output. Two summary modes are provided to control the level of detail in the provided output.

Features

  • Multiple tools for validating certificates

    • lscert CLI tool
      • verify certificate used by specified service
      • verify local certificate "bundle" or standalone leaf certificate file
    • check_cert Nagios plugin
      • verify certificate used by specified service
      • verify local certificate "bundle" or standalone leaf certificate file
    • certsum CLI tool
      • generate summary of discovered certificates from given hosts (single or IP Address ranges, hostnames or FQDNs) and ports
  • Check expiration of all certificates in the provided certificate chain for cert-enabled services

    • not expired
    • expiring "soon"
      • warning threshold
      • critical threshold
  • Validate provided hostname against Common Name or one of the available SANs entries (see configuration options)

  • Optional support for verifying SANs entries on a certificate against a provided list

    • if SKIPSANSCHECKS keyword is supplied as the value no SANs entry checks will be performed; this keyword is useful for defining a shared Nagios check command and service check where some hosts may not use a certificate which has SANs entries defined
  • Detailed "report" of findings

    • certificate order
    • certificate type
    • status (OK, CRITICAL, WARNING)
    • SANs entries
    • serial number
    • issuer
  • Optional generation of OpenSSL-like text output from target cert-enabled service or filename

    • thanks to the grantae/certinfo package
  • Optional, leveled logging using rs/zerolog package

    • JSON-format output (to stderr)
    • choice of disabled, panic, fatal, error, warn, info (the default), debug or trace.
  • Optional, user-specified timeout value for TCP connection attempt

Changelog

See the CHANGELOG.md file for the changes associated with each release of this application. Changes that have been merged to master, but not yet an official release may also be noted in the file under the Unreleased section. A helpful link to the Git commit history since the last official release is also provided for further review.

Requirements

The following is a loose guideline. Other combinations of Go and operating systems for building and running tools from this repo may work, but have not been tested.

Building source code

  • Go 1.13+
  • GCC
    • if building with custom options (as the provided Makefile does)
  • make
    • if using the provided Makefile

Running

  • Windows 7, Server 2008R2 or later
  • Windows 10 Version 1909
    • tested
  • Ubuntu Linux 16.04, 18.04

Installation

  1. Download Go
  2. Install Go
    • NOTE: Pay special attention to the remarks about $HOME/.profile
  3. Clone the repo
    1. cd /tmp
    2. git clone https://github.com/atc0005/check-cert
    3. cd check-cert
  4. Install dependencies (optional)
    • for Ubuntu Linux
      • sudo apt-get install make gcc
    • for CentOS Linux
      • sudo yum install make gcc
    • for Windows
      • Emulated environments (easier)
        • Skip all of this and build using the default go build command in Windows (see below for use of the -mod=vendor flag)
        • build using Windows Subsystem for Linux Ubuntu environment and just copy out the Windows binaries from that environment
        • If already running a Docker environment, use a container with the Go tool-chain already installed
        • If already familiar with LXD, create a container and follow the installation steps given previously to install required dependencies
      • Native tooling (harder)
        • see the StackOverflow Question 32127524 link in the References section for potential options for installing make on Windows
        • see the mingw-w64 project homepage link in the References section for options for installing gcc and related packages on Windows
  5. Build binaries
    • for the current operating system, explicitly using bundled dependencies in top-level vendor folder
      • go build -mod=vendor ./cmd/check_cert/
      • go build -mod=vendor ./cmd/lscert/
      • go build -mod=vendor ./cmd/fixsn/
      • go build -mod=vendor ./cmd/certsum/
    • for all supported platforms (where make is installed)
      • make all
    • for use on Windows
      • make windows
    • for use on Linux
      • make linux
  6. Copy the newly compiled binary from the applicable /tmp subdirectory path (based on the clone instructions in this section) below and deploy where needed.
    • if using Makefile
      • look in /tmp/check-cert/release_assets/check_cert/
      • look in /tmp/check-cert/release_assets/lscert/
      • look in /tmp/check-cert/release_assets/fixsn/
      • look in /tmp/check-cert/release_assets/certsum/
    • if using go build
      • look in /tmp/check-cert/

Configuration options

Threshold calculations

The behavior of the check_certplugin differs somewhat from check_http v2.1.2; this plugin triggers a whole day later than check_http does for the same WARNING and CRITICAL threshold values.

For example, if we use the default values of 30 days for WARNING threshold and 15 days for the CRITICAL threshold:

  1. The thresholds are calculated
    • WARNING: Now (exact time in UTC) + 30 days
    • CRITICAL: Now (exact time in UTC) + 15 days
  2. The certificate expiration date is checked and the very first match (in order) determines the status of the service check
    1. if the certificate expires before the current time, the status is EXPIRED
    2. if the certificate expires before the CRITICAL threshold, the status is CRITICAL
    3. if the certificate expires before the WARNING threshold, the status is WARNING
    4. otherwise, the certificate is assumed to have a status of OK

No rounding is performed.

See GH-32 for additional info.

Command-line arguments

  • Use the -h or --help flag to display current usage information.
  • Flags marked as required must be set via CLI flag.
  • Flags not marked as required are for settings where a useful default is already defined, but may be overridden if desired.

check_cert

Flag Required Default Repeat Possible Description
f, filename No false No valid file name characters Fully-qualified path to a PEM formatted certificate file containing one or more certificates.
branding No false No branding Toggles emission of branding details with plugin status details. This output is disabled by default.
h, help No false No h, help Show Help text along with the list of supported flags.
v, verbose No false No v, verbose Toggles emission of detailed certificate metadata. This level of output is disabled by default.
version No false No version Whether to display application version and then immediately exit application.
c, age-critical No 15 No positive whole number of days The threshold for the certificate check's CRITICAL state. If the certificate expires before this number of days then the service check will be considered in a CRITICAL state.
w, age-warning No 30 No positive whole number of days The threshold for the certificate check's WARNING state. If the certificate expires before this number of days, but not before the age-critical value, then the service check will be considered in a WARNING state.
ll, log-level No info No disabled, panic, fatal, error, warn, info, debug, trace Log message priority filter. Log messages with a lower level are ignored.
p, port No 443 No positive whole number between 1-65535, inclusive TCP port of the remote certificate-enabled service. This is usually 443 (HTTPS) or 636 (LDAPS).
t, timeout No 10 No positive whole number of seconds Timeout value in seconds allowed before a connection attempt to a remote certificate-enabled service (in order to retrieve the certificate) is abandoned and an error returned.
se, sans-entries No No comma-separated list of values One or many Subject Alternate Names (SANs) expected for the certificate used by the remote service. If provided, this list of comma-separated (optional) values is required for the certificate to pass validation. If the case-insensitive SKIPSANSCHECKS keyword is provided this validation will be skipped, effectively turning the use of this flag into a NOOP.
s, server Yes No fully-qualified domain name or IP Address The fully-qualified domain name or IP Address of the remote system whose cert(s) will be monitored. This value is used to make the connection to the server in order to retrieve the certificate chain. For hosts with only a single certificate, this value is often the FQDN of the host itself, but for multi-certificate servers the user-specified value will be crucial in order to allow the remote host to select the appropriate certificate (Server Name Indication support (SNI)). For websites hosted on those servers, it is necessary to instead provide the FQDN of the site instead of the server hostname. For example, specify www.example.org instead of host7.example.com. Specify the site FQDN if in doubt. The user-specified value will also be validated against the Common Name and Subject Alternate Names fields unless the dns-name flag is also specified, in which case this value is only used for making the initial connection.
dn, dns-name No No fully-qualified domain name or IP Address The fully-qualified domain name of the remote system to be used for hostname verification. This option can be used for cases where the initial connection is made using a name or IP Address not associated with the certificate. See the server flag description for more information.

lscert

Flag Required Default Repeat Possible Description
f, filename No false No valid file name characters Fully-qualified path to a PEM formatted certificate file containing one or more certificates.
text No false No true, false Toggles emission of x509 TLS certificates in an OpenSSL-inspired text format. This output is disabled by default.
h, help No false No h, help Show Help text along with the list of supported flags.
v, verbose No false No v, verbose Toggles emission of detailed certificate metadata. This level of output is disabled by default.
version No false No version Whether to display application version and then immediately exit application.
c, age-critical No 15 No positive whole number of days The threshold for the certificate check's CRITICAL state. If the certificate expires before this number of days then the service check will be considered in a CRITICAL state.
w, age-warning No 30 No positive whole number of days The threshold for the certificate check's WARNING state. If the certificate expires before this number of days, but not before the age-critical value, then the service check will be considered in a WARNING state.
ll, log-level No info No disabled, panic, fatal, error, warn, info, debug, trace Log message priority filter. Log messages with a lower level are ignored.
p, port No 443 No positive whole number between 1-65535, inclusive TCP port of the remote certificate-enabled service. This is usually 443 (HTTPS) or 636 (LDAPS).
t, timeout No 10 No positive whole number of seconds Timeout value in seconds allowed before a connection attempt to a remote certificate-enabled service (in order to retrieve the certificate) is abandoned and an error returned.
se, sans-entries No No comma-separated list of values One or many Subject Alternate Names (SANs) expected for the certificate used by the remote service. If provided, this list of comma-separated (optional) values is required for the certificate to pass validation. If the case-insensitive SKIPSANSCHECKS keyword is provided this validation will be skipped, effectively turning the use of this flag into a NOOP.
s, server Yes No fully-qualified domain name or IP Address The fully-qualified domain name or IP Address of the remote system whose cert(s) will be monitored. This value is used to make the connection to the server in order to retrieve the certificate chain. For hosts with only a single certificate, this value is often the FQDN of the host itself, but for multi-certificate servers the user-specified value will be crucial in order to allow the remote host to select the appropriate certificate (Server Name Indication support (SNI)). For websites hosted on those servers, it is necessary to instead provide the FQDN of the site instead of the server hostname. For example, specify www.example.org instead of host7.example.com. Specify the site FQDN if in doubt. The user-specified value will also be validated against the Common Name and Subject Alternate Names fields unless the dns-name flag is also specified, in which case this value is only used for making the initial connection.
dn, dns-name No No fully-qualified domain name or IP Address The fully-qualified domain name of the remote system to be used for hostname verification. This option can be used for cases where the initial connection is made using a name or IP Address not associated with the certificate. See the server flag description for more information.

fixsn

This tool does not accept any flags. Instead, it expects to receive just one argument: a base 10 formatted certificate serial number, handled internally as a *big.Int value. This value is converted to a base 16, colon-delimited hex string. This format is common to tooling used to examine certificates.

See the Examples section for usage.

certsum

This tool is in early development. Options for this tool are subject to change, perhaps even significantly, in future releases.

Flag Required Default Repeat Possible Description
h, help No false No h, help Show Help text along with the list of supported flags.
version No false No version Whether to display application version and then immediately exit application.
c, age-critical No 15 No positive whole number of days The threshold for the certificate check's CRITICAL state. If the certificate expires before this number of days then the service check will be considered in a CRITICAL state.
w, age-warning No 30 No positive whole number of days The threshold for the certificate check's WARNING state. If the certificate expires before this number of days, but not before the age-critical value, then the service check will be considered in a WARNING state.
ll, log-level No info No disabled, panic, fatal, error, warn, info, debug, trace Log message priority filter. Log messages with a lower level are ignored.
t, timeout No 10 No positive whole number of seconds Timeout value in seconds allowed before a connection attempt to a remote certificate-enabled service (in order to retrieve the certificate) is abandoned and an error returned.
se, sans-entries No No comma-separated list of values One or many Subject Alternate Names (SANs) expected for the certificate used by the remote service. If provided, this list of comma-separated (optional) values is required for the certificate to pass validation. If the case-insensitive SKIPSANSCHECKS keyword is provided this validation will be skipped, effectively turning the use of this flag into a NOOP.
st, scan-timeout No 200 No positive whole number of milliseconds, minimum 1 The number of milliseconds before a connection attempt during a port scan is abandoned and an error returned. This timeout value is separate from the general timeout value used when retrieving certificates. This setting is used specifically to quickly determine port state as part of bulk operations where speed is crucial.
at, app-timeout No 30 No positive whole number of seconds, minimum 2 The number of seconds the application is allowed to remain inactive (i.e., "hung") before it is automatically terminated.
srl, scan-rate-limit No 100 No positive whole number Maximum concurrent port and certificate scans. Remaining scans are queued until an existing scan completes.
ips, hosts No No one or more valid, comma-separated IP Addresses (single or range), hostnames or FQDNs List of comma-separated individual IP Addresses, CIDR IP ranges, partial (dash-separated) ranges (e.g., 192.168.2.10-15), hostnames or FQDNs to scan for certificates.
p, ports No 443 No one or more valid, comma-separated TCP ports List of comma-separated TCP ports to check for certificates. If not specified, the list defaults to 443 only.
spsr, show-port-scan-results No false No true, false Toggles listing host port scan results.
scp, show-closed-ports No false No true, false Toggles listing all host port scan results, even for hosts without any specified ports in an open state.
shwvc, show-hosts-with-valid-certs No false No true, false Toggles listing all cert check results in overview output, even for hosts with valid certificates.
svc, show-valid-certs No false No true, false Toggles listing all certificates in output summary, even certificates which have passed all validity checks.
so, show-overview No false No true, false Toggles summary output view from detailed to overview.

Configuration file

Not currently supported. This feature may be added later if there is sufficient interest.

Examples

check_cert Nagios plugin

OK results

This example shows using the Nagios plugin to manually check a remote certificate-enabled port on www.google.com. We override the default WARNING and CRITICAL age threshold values with somewhat arbitrary numbers.

NOTE: Use the --verbose flag to expose further details.

$ ./check_cert --server www.google.com --port 443 --age-critical 30 --age-warning 50
OK: leaf cert "www.google.com" expires next with 52d 16h remaining (until 2021-09-20 04:12:57 +0000 UTC) [EXPIRED: 0, EXPIRING: 0, OK: 3]

**ERRORS**

* None

**THRESHOLDS**

* CRITICAL: Expires before 2021-08-28 11:55:42 +0000 UTC (30 days)
* WARNING: Expires before 2021-09-17 11:55:42 +0000 UTC (50 days)

**DETAILED INFO**

Certificate 1 of 3 (leaf):
        Name: CN=www.google.com
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        Serial: 12:D4:D6:BA:D3:7B:1D:D1:0A:00:00:00:00:EB:61:08
        Issued On: 2021-06-28 04:12:58 +0000 UTC
        Expiration: 2021-09-20 04:12:57 +0000 UTC
        Status: [OK] 52d 16h remaining

Certificate 2 of 3 (intermediate):
        Name: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        Serial: 02:03:BC:53:59:6B:34:C7:18:F5:01:50:66
        Issued On: 2020-08-13 00:00:42 +0000 UTC
        Expiration: 2027-09-30 00:00:42 +0000 UTC
        Status: [OK] 2253d 12h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE
        Serial: 77:BD:0D:6C:DB:36:F9:1A:EA:21:0F:C4:F0:58:D3:0D
        Issued On: 2020-06-19 00:00:42 +0000 UTC
        Expiration: 2028-01-28 00:00:42 +0000 UTC
        Status: [OK] 2373d 12h remaining

See the WARNING example output for additional details.

WARNING results

Here we do the same thing again, but using the expiration date values returned earlier as a starting point, we intentionally move the threshold values in order to trigger a WARNING state for the leaf certificate: if the leaf certificate is good for 52 days and 16 hours more, we indicate that warnings that should trigger once the cert has fewer than 53 days left.

NOTE: Use the --verbose flag to expose further details.

$ ./check_c./check_cert --server www.google.com --port 443 --age-critical 30 --age-warning 53
{"level":"error","version":"check-cert v0.4.2-6-g934c303 (https://github.com/atc0005/check-cert)","logging_level":"info","app_type":"plugin","cert_check_timeout":"10s","age_warning":53,"age_critical":30,"expected_sans_entries":"","server":"www.google.com","port":443,"error":"1 certificates expired or expiring","expired_certs":0,"expiring_certs":1,"time":"2021-07-29T06:57:11-05:00","caller":"github.com/atc0005/check-cert/cmd/check_cert/main.go:241","message":"expired or expiring certs present in chain"}
WARNING: leaf cert "www.google.com" expires next with 52d 16h remaining (until 2021-09-20 04:12:57 +0000 UTC) [EXPIRED: 0, EXPIRING: 1, OK: 2]

**ERRORS**

* 1 certificates expired or expiring

**THRESHOLDS**

* CRITICAL: Expires before 2021-08-28 11:57:11 +0000 UTC (30 days)
* WARNING: Expires before 2021-09-20 11:57:11 +0000 UTC (53 days)

**DETAILED INFO**

Certificate 1 of 3 (leaf):
        Name: CN=www.google.com
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        Serial: 12:D4:D6:BA:D3:7B:1D:D1:0A:00:00:00:00:EB:61:08
        Issued On: 2021-06-28 04:12:58 +0000 UTC
        Expiration: 2021-09-20 04:12:57 +0000 UTC
        Status: [WARNING] 52d 16h remaining

Certificate 2 of 3 (intermediate):
        Name: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        Serial: 02:03:BC:53:59:6B:34:C7:18:F5:01:50:66
        Issued On: 2020-08-13 00:00:42 +0000 UTC
        Expiration: 2027-09-30 00:00:42 +0000 UTC
        Status: [OK] 2253d 12h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE
        Serial: 77:BD:0D:6C:DB:36:F9:1A:EA:21:0F:C4:F0:58:D3:0D
        Issued On: 2020-06-19 00:00:42 +0000 UTC
        Expiration: 2028-01-28 00:00:42 +0000 UTC
        Status: [OK] 2373d 12h remaining

Some items to note (in order of appearance):

  1. JSON output providing structured logging information
    • this is sent to stderr
    • Nagios ignores stderr output from plugins; stdout is for Nagios, stderr is for humans
  2. The one-line status output on the second line
    • this is used by Nagios for display in an overview view for all service checkout for a host
    • this is used by Nagios for text, email and whatever else notifications (if configured)
  3. The ERRORS section notes briefly what is wrong with the cert
  4. The CERTIFICATE AGE THRESHOLDS section notes what (calculated) thresholds were used to determine the current service check status (results)
  5. The DETAILED INFO section contains an overview of the certificate chain
    • this is used by Nagios for display on the detailed service check-specific page (e.g., shows last check time, frequency, current state, etc)
    • as for the one-line output, this is used by Nagios for text, email and whatever other notifications may be configured
  6. The Status field for the leaf certificate changed from OK to WARNING and this plugin set the appropriate exit code to let Nagios know of the state change.

CRITICAL results

Expiring certificate

As with the WARNING example, we use the expiration date values returned from the initial check as a starting point and intentionally move the threshold values in order to trigger a CRITICAL state for the leaf certificate: if the leaf certificate is good for 52 days and 16 hours more, we specify 90 days for the WARNING threshold and 60 days for the CRITICAL threshold. This triggers a CRITICAL state.

NOTE: Use the --verbose flag to expose further details.

$ ./check_c./check_cert --server www.google.com --port 443 --age-critical 60 --age-warning 90
{"level":"error","version":"check-cert v0.4.2-6-g934c303 (https://github.com/atc0005/check-cert)","logging_level":"info","app_type":"plugin","cert_check_timeout":"10s","age_warning":90,"age_critical":60,"expected_sans_entries":"","server":"www.google.com","port":443,"error":"1 certificates expired or expiring","expired_certs":0,"expiring_certs":1,"time":"2021-07-29T06:58:35-05:00","caller":"github.com/atc0005/check-cert/cmd/check_cert/main.go:241","message":"expired or expiring certs present in chain"}
CRITICAL: leaf cert "www.google.com" expires next with 52d 16h remaining (until 2021-09-20 04:12:57 +0000 UTC) [EXPIRED: 0, EXPIRING: 1, OK: 2]

**ERRORS**

* 1 certificates expired or expiring

**THRESHOLDS**

* CRITICAL: Expires before 2021-09-27 11:58:35 +0000 UTC (60 days)
* WARNING: Expires before 2021-10-27 11:58:35 +0000 UTC (90 days)

**DETAILED INFO**

Certificate 1 of 3 (leaf):
        Name: CN=www.google.com
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        Serial: 12:D4:D6:BA:D3:7B:1D:D1:0A:00:00:00:00:EB:61:08
        Issued On: 2021-06-28 04:12:58 +0000 UTC
        Expiration: 2021-09-20 04:12:57 +0000 UTC
        Status: [CRITICAL] 52d 16h remaining

Certificate 2 of 3 (intermediate):
        Name: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        Serial: 02:03:BC:53:59:6B:34:C7:18:F5:01:50:66
        Issued On: 2020-08-13 00:00:42 +0000 UTC
        Expiration: 2027-09-30 00:00:42 +0000 UTC
        Status: [OK] 2253d 12h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE
        Serial: 77:BD:0D:6C:DB:36:F9:1A:EA:21:0F:C4:F0:58:D3:0D
        Issued On: 2020-06-19 00:00:42 +0000 UTC
        Expiration: 2028-01-28 00:00:42 +0000 UTC
        Status: [OK] 2373d 12h remaining
Expired certificate

Here we use the expired.badssl.com subdomain to demo the results of encountering one or more (in this case more) expired certificates in a chain. Aside from the FQDN, all default options (including the port) are used.

NOTE: Use the --verbose flag to expose further details.

$ ./check_cert --server expired.badssl.com
{"level":"error","version":"check-cert v0.4.2-6-g934c303 (https://github.com/atc0005/check-cert)","logging_level":"info","app_type":"plugin","cert_check_timeout":"10s","age_warning":30,"age_critical":15,"expected_sans_entries":"","server":"expired.badssl.com","port":443,"error":"2 certificates expired or expiring","expired_certs":2,"expiring_certs":0,"time":"2021-07-29T07:02:17-05:00","caller":"github.com/atc0005/check-cert/cmd/check_cert/main.go:241","message":"expired or expiring certs present in chain"}
CRITICAL: leaf cert "*.badssl.com" expired 2299d 12h ago (on 2015-04-12 23:59:59 +0000 UTC) [EXPIRED: 2, EXPIRING: 0, OK: 1]

**ERRORS**

* 2 certificates expired or expiring

**THRESHOLDS**

* CRITICAL: Expires before 2021-08-13 12:02:16 +0000 UTC (15 days)
* WARNING: Expires before 2021-08-28 12:02:16 +0000 UTC (30 days)

**DETAILED INFO**

Certificate 1 of 3 (leaf):
        Name: CN=*.badssl.com,OU=Domain Control Validated+OU=PositiveSSL Wildcard
        SANs entries: [*.badssl.com badssl.com]
        Issuer: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        Serial: 4A:E7:95:49:FA:9A:BE:3F:10:0F:17:A4:78:E1:69:09
        Issued On: 2015-04-09 00:00:00 +0000 UTC
        Expiration: 2015-04-12 23:59:59 +0000 UTC
        Status: [EXPIRED] 2299d 12h ago

Certificate 2 of 3 (intermediate):
        Name: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        SANs entries: []
        Issuer: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        Serial: 2B:2E:6E:EA:D9:75:36:6C:14:8A:6E:DB:A3:7C:8C:07
        Issued On: 2014-02-12 00:00:00 +0000 UTC
        Expiration: 2029-02-11 23:59:59 +0000 UTC
        Status: [OK] 2754d 11h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        SANs entries: []
        Issuer: CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
        Serial: 27:66:EE:56:EB:49:F3:8E:AB:D7:70:A2:FC:84:DE:22
        Issued On: 2000-05-30 10:48:38 +0000 UTC
        Expiration: 2020-05-30 10:48:38 +0000 UTC
        Status: [EXPIRED] 425d 1h ago

lscert CLI tool

OK results

This example shows using the CLI app to perform the same initial check that we performed earlier using the Nagios plugin.

NOTE: Use the --verbose flag to expose further details.

$ ./lscert --server www.google.com --port 443 --age-critical 50 --age-warning 55

Connecting to remote server "www.google.com" at port 443


=============================
CERTIFICATES | AGE THRESHOLDS
=============================

- WARNING:      Expires before 2020-08-30 11:12:01 +0000 UTC (55 days)
- CRITICAL:     Expires before 2020-08-25 11:12:01 +0000 UTC (50 days)


======================
CERTIFICATES | SUMMARY
======================

- OK: 2 certs found for service running on www.google.com at port 443
- OK: Provided hostname matches discovered certificate
- OK: leaf cert "www.google.com" expires next with 65d 3h remaining (until 2020-09-09 14:31:22 +0000 UTC)
- OK: [EXPIRED: 0, EXPIRING: 0, OK: 2]


============================
CERTIFICATES | CHAIN DETAILS
============================

Certificate 1 of 2 (leaf):
        Name: CN=www.google.com,O=Google LLC,L=Mountain View,ST=California,C=US
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1O1,O=Google Trust Services,C=US
        Serial: FD:6F:3E:24:98:C2:5B:1D:08:00:00:00:00:47:F0:33
        Expiration: 2020-09-09 14:31:22 +0000 UTC
        Status: [OK] 65d 3h remaining

Certificate 2 of 2 (intermediate):
        Name: CN=GTS CA 1O1,O=Google Trust Services,C=US
        SANs entries: []
        Issuer: CN=GlobalSign,OU=GlobalSign Root CA - R2,O=GlobalSign
        Serial: 01:E3:B4:9A:A1:8D:8A:A9:81:25:69:50:B8
        Expiration: 2021-12-15 00:00:42 +0000 UTC
        Status: [OK] 526d 12h remaining

WARNING results

NOTE: Use the --verbose flag to expose further details.

$ ./lscert --server www.google.com --port 443 --age-critical 50 --age-warning 66

Connecting to remote server "www.google.com" at port 443


=============================
CERTIFICATES | AGE THRESHOLDS
=============================

- WARNING:      Expires before 2020-09-10 11:13:11 +0000 UTC (66 days)
- CRITICAL:     Expires before 2020-08-25 11:13:11 +0000 UTC (50 days)


======================
CERTIFICATES | SUMMARY
======================

- OK: 2 certs found for service running on www.google.com at port 443
- OK: Provided hostname matches discovered certificate
- WARNING: leaf cert "www.google.com" expires next with 65d 3h remaining (until 2020-09-09 14:31:22 +0000 UTC)
- WARNING: [EXPIRED: 0, EXPIRING: 1, OK: 1]


============================
CERTIFICATES | CHAIN DETAILS
============================

Certificate 1 of 2 (leaf):
        Name: CN=www.google.com,O=Google LLC,L=Mountain View,ST=California,C=US
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1O1,O=Google Trust Services,C=US
        Serial: FD:6F:3E:24:98:C2:5B:1D:08:00:00:00:00:47:F0:33
        Expiration: 2020-09-09 14:31:22 +0000 UTC
        Status: [WARNING] 65d 3h remaining

Certificate 2 of 2 (intermediate):
        Name: CN=GTS CA 1O1,O=Google Trust Services,C=US
        SANs entries: []
        Issuer: CN=GlobalSign,OU=GlobalSign Root CA - R2,O=GlobalSign
        Serial: 01:E3:B4:9A:A1:8D:8A:A9:81:25:69:50:B8
        Expiration: 2021-12-15 00:00:42 +0000 UTC
        Status: [OK] 526d 12h remaining

In general, the differences between the OK and WARNING output for the two tools is minor. However, unlike the check_cert Nagios plugin where we are limited to one line of summary output, the lscert CLI tool doesn't share the same output requirements and can be more expressive (e.g., such as the summary section to highlight particular items of interest). Like the check_cert Nagios plugin, the lscert CLI tool also displays the thresholds used to determine the state of the checks applied to the certificate chain.

CRITICAL results

Here we use the expired.badssl.com subdomain to demo the results of encountering one or more (in this case more) expired certificates in a chain. Aside from the FQDN, all default options (including the port) are used.

NOTE: Use the --verbose flag to expose further details.

$ ./lscert --server expired.badssl.com

Connecting to remote server "expired.badssl.com" at port 443


=============================
CERTIFICATES | AGE THRESHOLDS
=============================

- WARNING:      Expires before 2020-08-05 11:14:32 +0000 UTC (30 days)
- CRITICAL:     Expires before 2020-07-21 11:14:32 +0000 UTC (15 days)


======================
CERTIFICATES | SUMMARY
======================

- OK: 3 certs found for service running on expired.badssl.com at port 443
- OK: Provided hostname matches discovered certificate
- CRITICAL: leaf cert "*.badssl.com" expired 1911d 11h ago (on 2015-04-12 23:59:59 +0000 UTC)
- CRITICAL: [EXPIRED: 2, EXPIRING: 0, OK: 1]


============================
CERTIFICATES | CHAIN DETAILS
============================

Certificate 1 of 3 (leaf):
        Name: CN=*.badssl.com,OU=Domain Control Validated+OU=PositiveSSL Wildcard
        SANs entries: [*.badssl.com badssl.com]
        Issuer: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        Serial: 4A:E7:95:49:FA:9A:BE:3F:10:0F:17:A4:78:E1:69:09
        Expiration: 2015-04-12 23:59:59 +0000 UTC
        Status: [EXPIRED] 1911d 11h ago

Certificate 2 of 3 (intermediate):
        Name: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        SANs entries: []
        Issuer: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        Serial: 2B:2E:6E:EA:D9:75:36:6C:14:8A:6E:DB:A3:7C:8C:07
        Expiration: 2029-02-11 23:59:59 +0000 UTC
        Status: [OK] 3142d 12h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        SANs entries: []
        Issuer: CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
        Serial: 27:66:EE:56:EB:49:F3:8E:AB:D7:70:A2:FC:84:DE:22
        Expiration: 2020-05-30 10:48:38 +0000 UTC
        Status: [EXPIRED] 37d 0h ago

Some items to note in the CERTIFICATES | SUMMARY section:

  • the certificate which expired first (leaf cert *.badssl.com) is listed
    • chain position
    • expiration summary
    • expiration date
  • a quick count of the EXPIRED, EXPIRING and OK certificates
  • future work here might list out all expired certs, but the assumption was that listing the first one to expire and then listing out the chain details in the following section (with explicit notes re expiration status) was sufficient coverage

fixsn CLI tool

Invalid input

$ ./fixsn badinput
Error: Invalid serial number (in base 10 format)
Example expected input: 336872288293767042001244177974291853363

Expected input

$ ./fixsn 336872288293767042001244177974291853363
FD:6F:3E:24:98:C2:5B:1D:08:00:00:00:00:47:F0:33

certsum CLI tool

This tool is in early development and options available are subject to change (perhaps even significantly) in future releases.

Please see the list of available flags/options documented earlier in this README for further options.

Certificates Overview

The following options generate a one-liner, high-level overview for each host with a certificate. Hosts without a certificate are omitted from the results.

$ ./certsum --hosts 192.168.5.0/24 --show-hosts-with-valid-certs --show-overview
Beginning cert scan against 254 unique hosts using ports: [443]
...................
Completed certificates scan in 2.3670248s
19 certificates (8 issues) found.

Results (all):

IP Address            Port    Subject or SANs                       Status          Chain Summary                           Serial
---                   ---     ---                                   ---             ---                                     ---
192.168.5.22          443     VMware                                ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        92:4A:AD:38:3C:DC:C1:B6
192.168.5.3           443     VMware                                ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        DE:FD:50:2B:C5:7F:79:F4
192.168.5.24          443     VMware                                ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        9A:DF:A1:A6:60:16:4E:C0
192.168.5.11          443     VMware                                ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        8D:2C:61:CF:AE:57:58:98
192.168.5.83          443     HP Jetdirect 4639304E                 ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        47:F0:56:50
192.168.5.109         443     HP LaserJet M506 F2A68A               ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        -29:25:F5:A8:D5:E2:FC:C3:71:77:F4:48:3A:09:2E:24:0F:0E:37:1A
192.168.5.93          443     NPI25BC25                             ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        -61:CE:BD:13
192.168.5.113         443     NPI253CDE                             ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        38:BC:BD:21
192.168.5.136         443     HP Jetdirect BAC74492                 ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        20:46:94:C0
192.168.5.104         443     HP Jetdirect 7FE7AF22                 ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        02
192.168.5.165         443     192.168.5.165                         ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        EF:E5:A3:0E:2F:FA:C1:3A
192.168.5.183         443     192.168.5.183                         ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        F7:A2:CD:4A:F2:A0:63:10
192.168.5.182         443     192.168.5.182                         ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        AC:53:68:BB:38:5E:5A:6C
192.168.5.105         443     192.168.5.105                         ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        64:36:33:33:32:36:37:38:30:31:64:66:37:31:31:62:32:62:37:63

Of note:

  • implicitly use the default port of 443/tcp
  • scan the entire 192.168.5.0/24 range
  • generate output in the overview or summary format
  • show "OK" hosts alongside problem hosts (usually omitted for brevity)

CIDR range

$ ./certsum --ports 443 --hosts 192.168.5.0/24
Total IPs from all ranges before deduping: 254
Total IPs from all ranges after deduping: 254
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
..........................
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                 Status (Type)                   Summary                         Serial
---                     ---     ---                             ---                             ---                             ---
192.168.5.104           443     HP Jetdirect 7FE7AF22           ⛔ (leaf; self-signed)          [EXPIRED] 3942d 12h ago         02
192.168.5.3             443     VMware                          ⛔ (root)                       [EXPIRED] 571d 23h ago          DE:FD:50:2B:C5:7F:79:F4
192.168.5.109           443     HP LaserJet M506 F2A68A         ⛔ (leaf; self-signed)          [CRITICAL] 1d 7h remaining      -29:25:F5:A8:D5:E2:FC:C3:71:77:F4:48:3A:09:2E:24:0F:0E:37:1A
192.168.5.83            443     HP Jetdirect 4639304E           ⛔ (leaf; self-signed)          [EXPIRED] 2175d 12h ago         47:F0:56:50
192.168.5.165           443     192.168.5.165                   ⛔ (leaf; self-signed)          [EXPIRED] 1519d 7h ago          EF:E5:A3:0E:2F:FA:C1:3A
192.168.5.183           443     192.168.5.183                   ⛔ (leaf; self-signed)          [EXPIRED] 1034d 19h ago         F7:A2:CD:4A:F2:A0:63:10

Of note:

  • explicitly specify port 443/tcp (the default)
  • scan the entire 192.168.5.0/24 range
  • only emit "problem" entries

Partial range

Here we specify a partial range using a syntax intentionally similar to the octet based addressing syntax accepted by nmap (an amazing tool). Commas within an octet (in order to exclude IPs) are not supported at this time.

$ ./certsum --ports 443 --hosts 192.168.5.104-110
Total IPs from all ranges before deduping: 6
Total IPs from all ranges after deduping: 6
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
..........................
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                 Status (Type)                   Summary                         Serial
---                     ---     ---                             ---                             ---                             ---
192.168.5.104           443     HP Jetdirect 7FE7AF22           ⛔ (leaf; self-signed)          [EXPIRED] 3942d 12h ago         02
192.168.5.109           443     HP LaserJet M506 F2A68A         ⛔ (leaf; self-signed)          [CRITICAL] 1d 7h remaining      -29:25:F5:A8:D5:E2:FC:C3:71:77:F4:48:3A:09:2E:24:0F:0E:37:1A

Partial range and a single IP Address

$ ./certsum --ports 443 --hosts 192.168.5.3,192.168.5.104-110
Total IPs from all ranges before deduping: 7
Total IPs from all ranges after deduping: 7
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
..........................
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                 Status (Type)                   Summary                         Serial
---                     ---     ---                             ---                             ---                             ---
192.168.5.3             443     VMware                          ⛔ (root)                       [EXPIRED] 577d 0h ago           DE:FD:50:2B:C5:7F:79:F4
192.168.5.104           443     HP Jetdirect 7FE7AF22           ⛔ (leaf; self-signed)          [EXPIRED] 3942d 12h ago         02
192.168.5.109           443     HP LaserJet M506 F2A68A         ⛔ (leaf; self-signed)          [CRITICAL] 1d 7h remaining      -29:25:F5:A8:D5:E2:FC:C3:71:77:F4:48:3A:09:2E:24:0F:0E:37:1A

Partial range, CIDR range and a single IP Address

$ ./certsum --ports 443 --hosts 192.168.5.3,192.168.5.104-110,192.168.2.0/24
Total IPs from all ranges before deduping: 260
Total IPs from all ranges after deduping: 260
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
...............................................................

Only the lead-in text is included as the output closely matches the other examples.

Single IP Address and a FQDN

Of note:

  • Default HTTPS port (because we did not specify one)
  • We are using a FQDN
$ ./certsum --hosts 192.168.5.3,expired.badssl.com
Total IPs from all ranges before deduping: 2
Total IPs from all ranges after deduping: 2
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
..
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                                 Status (Type)           Summary                         Serial
---                     ---     ---                                             ---                     ---                             ---
192.168.5.3             443     VMware                                          ⛔ (root)               [EXPIRED] 577d 0h ago           DE:FD:50:2B:C5:7F:79:F4
104.154.89.105          443     badssl-fallback-unknown-subdomain-or-no-sni     ⛔ (leaf)               [EXPIRED] 865d 13h ago          CD:BC:5A:4A:EC:97:67:B1

Show all scan results

We include an additional scan target without a certificate to illustrate what would normally be muted/hidden away with the default scan results.

$ ./certsum --hosts 192.168.5.3,expired.badssl.com,scanme.nmap.org --show-valid-certs --show-port-scan-results --show-hosts-with-valid-certs --show-closed-ports
Total IPs from all ranges before deduping: 4
Total IPs from all ranges after deduping: 4
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
192.168.5.3: [443: true]
104.154.89.105: [443: true]
45.33.32.156: [None]
2600:3c01::f03c:91ff:fe18:bb2f: [None]
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                                 Status (Type)           Summary                         Serial
---                     ---     ---                                             ---                     ---                             ---
192.168.5.3             443     VMware                                          ⛔ (root)               [EXPIRED] 577d 21h ago          DE:FD:50:2B:C5:7F:79:F4
104.154.89.105          443     badssl-fallback-unknown-subdomain-or-no-sni     ⛔ (leaf)               [EXPIRED] 865d 13h ago          CD:BC:5A:4A:EC:97:67:B1

License

From the LICENSE file:

MIT License

Copyright (c) 2020 Adam Chalkley

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

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.

References

Owner
Adam Chalkley
Perpetually searching, optimistically motivated
Adam Chalkley
Comments
  • Expiring certificate was flagged one day after official check_http Nagios plugin did so

    Expiring certificate was flagged one day after official check_http Nagios plugin did so

    We had a deprecated cert expiration check trigger last night at 7 pm (I think it was). This is the output for that deprecated check:

    expires in 30 day(s) (Sat 01 Aug 2020 12:59:00 AM CDT)

    Output for the new check (specific to the leaf cert):

    expires next (on 2020-07-31 23:59:59 +0000 UTC)

    and from the "Detailed Info" block:

    Expiration: 2020-07-31 23:59:59 +0000 UTC

    I suspect that all time/date comparisons are being performed in UTC already, but I want to double-check and ensure that is the case. If so, I'm not too concerned (based on my current understanding) that the old check is in local time and the new one (presumably) is in UTC.

    In short: I'd want to have the comparison time zones match, so if the cert expiration is in UTC, then I think we should compare based on UTC.

  • Expired (version 1) CA certificate misidentified as leaf certificate

    Expired (version 1) CA certificate misidentified as leaf certificate

    Output from a current dev build of the lscert application:

    Certificate 2 of 4 (intermediate):
            Name: SERIALNUMBER=07969287,CN=Go Daddy Secure Certification Authority,OU=http://certificates.godaddy.com/repository,O=GoDaddy.com\, Inc.,L=Scottsdale,ST=Arizona,C=US
            SANs entries: []
            KeyID: FD:AC:61:32:93:6C:45:D6:E2:EE:85:5F:9A:BA:E7:76:99:68:CC:E7
            Issuer: OU=Go Daddy Class 2 Certification Authority,O=The Go Daddy Group\, Inc.,C=US
            IssuerKeyID: D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
            Serial: 03:01
            Issued On: 2006-11-16 01:54:37 +0000 UTC
            Expiration: 2026-11-16 01:54:37 +0000 UTC
            Status: [OK] 2163d 12h remaining
    
    Certificate 3 of 4 (intermediate):
            Name: OU=Go Daddy Class 2 Certification Authority,O=The Go Daddy Group\, Inc.,C=US
            SANs entries: []
            KeyID: D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
            Issuer: CN=http://www.valicert.com/,OU=ValiCert Class 2 Policy Validation Authority,O=ValiCert\, Inc.,L=ValiCert Validation Network,1.2.840.113549.1.9.1=#0c11696e666f4076616c69636572742e636f6d
            IssuerKeyID:
            Serial: 01:0D
            Issued On: 2004-06-29 17:06:20 +0000 UTC
            Expiration: 2024-06-29 17:06:20 +0000 UTC
            Status: [OK] 1294d 4h remaining
    
    Certificate 4 of 4 (leaf):
            Name: CN=http://www.valicert.com/,OU=ValiCert Class 2 Policy Validation Authority,O=ValiCert\, Inc.,L=ValiCert Validation Network,1.2.840.113549.1.9.1=#0c11696e666f4076616c69636572742e636f6d
            SANs entries: []
            KeyID:
            Issuer: CN=http://www.valicert.com/,OU=ValiCert Class 2 Policy Validation Authority,O=ValiCert\, Inc.,L=ValiCert Validation Network,1.2.840.113549.1.9.1=#0c11696e666f4076616c69636572742e636f6d
            IssuerKeyID:
            Serial: 01
            Issued On: 1999-06-26 00:19:54 +0000 UTC
            Expiration: 2019-06-26 00:19:54 +0000 UTC
            Status: [EXPIRED] 536d 12h ago
    

    The current logic for determining the chain position:

    https://github.com/atc0005/check-cert/blob/469890cc28b51ba140366549bad270d2adead404/internal/certs/certs.go#L318-L340

  • Add support for explicitly applying or ignoring specific validation check results

    Add support for explicitly applying or ignoring specific validation check results

    Currently the check_cert plugin and lscert CLI tool requires that:

    • at least one cert is present
    • any certs present in the chain are not expired
    • that the expiration thresholds have not been crossed (implicit or explicit)
    • that the hostname matches
      • see also the dns-name flag

    These validation options are currently not implemented:

    • name constraints
      • e.g., don't allow a leaf cert to claim a name that the intermediate did not authorize
    • valid chain from leaf to root (GH-2)
    • ?

    Not sure of the final form, but it may be useful to offer a one-stop flag to control which validation settings are applied.

  • Clarify SNI support for systems with multiple certificate chains

    Clarify SNI support for systems with multiple certificate chains

    Today I wired up a Nginx instance to (temporarily) use an additional key and certificate normally used by another system. Web browsers (at least those that are SNI-capable) are very happy with the results, but the current version of this tool is flagging the first certificate that it found as being problematic.

    Templated version of the Nagios report:

    hostname subdomain.example.com does not match first cert in chain www.example.com

    ERRORS

    x509: certificate is valid for www.example.com, example.com, not subdomain.example.com

    I believe that the Nginx configuration has this "guest" (temporary) certificate as the first one, mostly because the existing system has a lower-level importance than the site it is temporarily standing in for.

    The next step is to research how to best support SNI: enabled by default (find all certs that it can), via an optional --sni flag, or something else entirely?

  • Certificate serial number reported in wrong format

    Certificate serial number reported in wrong format

    Problem

    When testing a prototype for a future tool (#103), I found that a self-signed certificate for a printer's web UI had a negative serial number. Looking closer, I found that all serial numbers that have been reported since v0.1.0 have been in an incorrect format.

    From a README example:

    Certificate 1 of 2 (leaf):
            Name: CN=www.google.com,O=Google LLC,L=Mountain View,ST=California,C=US
            SANs entries: [www.google.com]
            KeyID: 8E:A3:6C:47:12:A7:A:7:5B:94:51:D6:2A:3F:72:F9:35:6:45:2C
            Issuer: CN=GTS CA 1O1,O=Google Trust Services,C=US
            IssuerKeyID: 98:D1:F8:6E:10:EB:CF:9B:EC:60:9F:18:90:1B:A0:EB:7D:9:FD:2B
            Serial: 336872288293767042001244177974291853363
            Expiration: 2020-09-09 14:31:22 +0000 UTC
            Status: [WARNING] 65d 3h remaining
    

    Looking at the code, I find:

    https://github.com/atc0005/check-cert/blob/6b1fad083faca657d60a7efcf29dde931f566c4b/internal/certs/certs.go#L339

    https://github.com/atc0005/check-cert/blob/6b1fad083faca657d60a7efcf29dde931f566c4b/internal/certs/certs.go#L357

    and according to the docs (https://golang.org/pkg/math/big/#Int.String), the Stringer interface:

    String returns the decimal representation of x as generated by x.Text(10).

    Which means that technically the output is the right serial number, it isn't in the hex format that everyone is used to working with.

    Which means that this line in the README example (base 10):

            Serial: 336872288293767042001244177974291853363
    

    should have been (base 16):

            Serial: FD6F3E2498C25B1D080000000047F033
    

    Code snippet

    Conversion

    Code to convert base 10 *bit.Int output to base 16:

    package main
    
    import (
    	"fmt"
    	"math/big"
    )
    
    func main() {
    	serialNumber := new(big.Int)
    	serialNumber.SetString("336872288293767042001244177974291853363", 10)
    	fmt.Printf("%v\n", serialNumber.Text(16))
    }
    

    Output:

    fd6f3e2498c25b1d080000000047f033
    

    Display negative serial number

    package main
    
    import (
    	"crypto/x509"
    	"encoding/pem"
    	"fmt"
    )
    
    func main() {
    	certPEM := `-----BEGIN CERTIFICATE-----
    MIICNjCCAeCgAwIBAgIQgHCUCGAAkJMR0ub/9x4viDANBgkqhkiG9w0BAQQFADB9
    MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZp
    ZXcxJTAjBgNVBAoTHE5ldHNjYXBlIENvbW11bmljYXRpb25zIENvcnAxDTALBgNV
    BAsTBEFQTUMxEzARBgNVBAMTClJ1c2xhbkF1dGgwHhcNOTkwMzMxMDAzMzA3WhcN
    MDQwMzMxMDAzMzA3WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNV
    BAcTDU1vdW50YWluIFZpZXcxJTAjBgNVBAoTHE5ldHNjYXBlIENvbW11bmljYXRp
    b25zIENvcnAxDTALBgNVBAsTBEFQTUMxEzARBgNVBAMTClJ1c2xhbkF1dGgwXDAN
    BgkqhkiG9w0BAQEFAANLADBIAkEAxu9LmRU3GHSS9q/TQbF4iNZhbNETm0Jg+NzA
    /5QSY59YYAfitOEyc9gkrtQ3ZUJWhiZeLR+4/75YVQaY1/wRAwIDAQABozwwOjAL
    BgNVHQ8EBAMCAcQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQURK5ym9yBRRjrO1yX
    /dPjZc2Vyu0wDQYJKoZIhvcNAQEEBQADQQCsaps5vJ3eRQPx1gGaah6yCOfviIj0
    wSo4P9N2TvXyAnxV7GZGc+9kqGejHVTdFcG9K1Ygjz/azvd3Jpsee0dc
    -----END CERTIFICATE-----`
    
    	block, _ := pem.Decode([]byte(certPEM))
    	if block == nil {
    		panic("failed to parse certificate PEM")
    	}
    
    	cert, err := x509.ParseCertificate(block.Bytes)
    	if err != nil {
    		panic("failed to parse certificate: " + err.Error())
    	}
    
    	fmt.Printf("%X", cert.SerialNumber)
    }
    

    References

    • Go

      • https://github.com/golang/go/issues/8265
      • https://go-review.googlesource.com/c/go/+/17247
    • Examples of working around/with negative serial numbers

      • https://github.com/mock-server/mockserver/issues/214
      • https://github.com/zmap/zgrab/commit/a3d044e4605b663d946cbe47d22fc952562506fb
      • https://github.com/mozilla/tls-observatory/issues/184
    • Standards discussion around non-negative serial numbers

      • https://www.ietf.org/rfc/rfc3280.txt
      • https://security.stackexchange.com/questions/51800/why-does-the-rfc-5280-dictate-the-cas-not-to-issue-certificates-with-negative-se
    • Code

      • https://play.golang.org/p/G3Op7t9KzS
  • lscert | Positional argument parsing appears to cause valid flags to be ignored

    lscert | Positional argument parsing appears to cause valid flags to be ignored

    Overview

    Steps to reproduce:

    cd /path/to/repo
    go build ./cmd/lscert
    ./lscert https://example.com:443/ --port 8443 --log-level debug --help
    

    Neither the port, log-level or help flags are honored.

    References

    • GH-378
  • Add support for partial IP ranges and hostname/FQDN values

    Add support for partial IP ranges and hostname/FQDN values

    Currently a list of whole CIDR IP ranges is accepted and processed (and deduped), but we won't always require scanning a complete CIDR range/subnet, but instead a small portion of hosts out of a range. We might also wish to toss in single IP Addresses for scanning as well. While I believe it would be possible to specify a mask that allows for inclusion of individual IPs, this does not make for a very friendly UI.

    This might be acceptable if a config file was the chosen interface, but that is not the intended approach for using this tool (yet).

  • x509: certificate relies on legacy Common Name field, use SANs instead

    x509: certificate relies on legacy Common Name field, use SANs instead

    Overview

    Recent versions of check_cert and lscert emit this error message when encountering certificates missing Subject Alternate Names (SANs) entries:

    x509: certificate relies on legacy Common Name field, use SANs instead

    As detailed by GH-70, Go deprecated support for using the Common Name field to verify hostnames when encountering an empty SANs list. Go 1.16 reiterated this deprecation and Go 1.17 removed the support.

    This project switched to Go 1.17 for the v0.5.4 release in preparation for Go 1.16 going EOL in Q1 2022.

    While restoring Common Name verification is technically possible, it's not a viable direction for this project. Instead, we should attempt to gracefully handle this scenario when encountered and provide useful feedback to the user so that they can best decide next steps to resolve the issue.

    Workarounds:

    • use binaries from the v0.5.3 release
    • rebuild current codebase using Go 1.16

    References

    • GH-70
    • https://go.dev/doc/go1.15#commonname
    • https://go.dev/doc/go1.16#crypto/x509
    • https://go.dev/doc/go1.17#crypto/x509
    • https://chromestatus.com/feature/4981025180483584
    • https://developers.google.com/web/updates/2017/03/chrome-58-deprecations#remove_support_for_commonname_matching_in_certificates
    • https://frasertweedale.github.io/blog-redhat/posts/2017-07-11-cn-deprecation.html
  • Add `--verbose` (or similar) flag to display fingerprints/thumbprints of certs in chain

    Add `--verbose` (or similar) flag to display fingerprints/thumbprints of certs in chain

    Needed to see one of SHA1, SHA256 or SHA512 fingerprints on a cert this AM to make a visual comparison against what an app was showing me, but was reminded that this detail was not displayed.

    It would be useful to have this detail (and potentially others) displayed when a --verbose flag is provided. It might be that some existing details (e.g., KeyID, IssuerKeyID) could be moved behind such a flag in order to streamline the "basic" or default view some.

  • Certificates crossing the CRITICAL threshold are not flagged as CRITICAL state

    Certificates crossing the CRITICAL threshold are not flagged as CRITICAL state

    I believe this works as intended, but when reviewing this project as part of work on a new one this block stuck out:

    https://github.com/atc0005/check-cert/blob/999506d4ce0ca3f33f017dd356b74f02fab23649/cmd/check_cert/main.go#L222-L266

    At a glance, this looks like crossing the CRITICAL age threshold will only result in a WARNING state up until the certificate expires. I'm pretty sure this isn't the case though, but it's worth a more thorough review just to be sure.

  • Update cert chain summary output to include the 'Not Before' value also

    Update cert chain summary output to include the 'Not Before' value also

    Currently the 'Not After' value is exposed as the Expiration value in the summary output.

    Example from checking github.com via the lscert tool:

    $ lscert --server github.com
    
    Connecting to remote server "github.com" at port 443
    
    
    =============================
    CERTIFICATES | AGE THRESHOLDS
    =============================
    
    - WARNING:      Expires before 2020-12-05 15:42:50 +0000 UTC (30 days)
    - CRITICAL:     Expires before 2020-11-20 15:42:50 +0000 UTC (15 days)
    
    
    ======================
    CERTIFICATES | SUMMARY
    ======================
    
    - OK: 2 certs found for service running on github.com at port 443
    - OK: Provided hostname matches discovered certificate
    - OK: leaf cert "github.com" expires next with 550d 20h remaining (until 2022-05-10 12:00:00 +0000 UTC)
    - OK: [EXPIRED: 0, EXPIRING: 0, OK: 2]
    
    
    ============================
    CERTIFICATES | CHAIN DETAILS
    ============================
    Certificate 1 of 2 (leaf):
            Name: CN=github.com,O=GitHub\, Inc.,L=San Francisco,ST=California,C=US
            SANs entries: [github.com www.github.com]
            KeyID: 63:2:D2:5D:2:5F:F7:8D:D5:5A:12:9E:76:11:36:96:86:2C:8A:48
            Issuer: CN=DigiCert SHA2 High Assurance Server CA,OU=www.digicert.com,O=DigiCert Inc,C=US
            IssuerKeyID: 51:68:FF:90:AF:2:7:75:3C:CC:D9:65:64:62:A2:12:B8:59:72:3B
            Serial: 7101927171473588541993819712332065657
            Expiration: 2022-05-10 12:00:00 +0000 UTC
            Status: [OK] 550d 20h remaining
    
    Certificate 2 of 2 (intermediate):
            Name: CN=DigiCert SHA2 High Assurance Server CA,OU=www.digicert.com,O=DigiCert Inc,C=US
            SANs entries: []
            KeyID: 51:68:FF:90:AF:2:7:75:3C:CC:D9:65:64:62:A2:12:B8:59:72:3B
            Issuer: CN=DigiCert High Assurance EV Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US
            IssuerKeyID: B1:3E:C3:69:3:F8:BF:47:1:D4:98:26:1A:8:2:EF:63:64:2B:C3
            Serial: 6489877074546166222510380951761917343
            Expiration: 2028-10-22 12:00:00 +0000 UTC
            Status: [OK] 2907d 20h remaining
    

    Adding the 'Not Before' value (not sure of label name yet) would be helpful in fairly quickly identifying when a cert was generated/replaced.

  • go.mod: bump github.com/mattn/go-isatty from 0.0.16 to 0.0.17

    go.mod: bump github.com/mattn/go-isatty from 0.0.16 to 0.0.17

    Bumps github.com/mattn/go-isatty from 0.0.16 to 0.0.17.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • go.mod: bump golang.org/x/sys from 0.3.0 to 0.4.0

    go.mod: bump golang.org/x/sys from 0.3.0 to 0.4.0

    Bumps golang.org/x/sys from 0.3.0 to 0.4.0.

    Commits
    • b60007c unix: add Uvmexp and SysctlUvmexp for NetBSD
    • b751db5 unix: gofmt hurd files after CL 459895
    • b360406 unix: support TIOCGETA on GNU/Hurd
    • 3086868 unix: regen on OpenBSD 7.2
    • 2b11e6b unix: remove Mclpool from openbsd types
    • 7c6badc unix: convert openbsd/mips64 to direct libc calls
    • 3b1fc93 unix: avoid allocations for common uses of Readv, Writev, etc.
    • 2204b66 cpu: parse /proc/cpuinfo on linux/arm64 on old kernels when needed
    • 72f772c unix: offs2lohi should shift by bits, not bytes
    • cffae8e unix: add ClockGettime on *bsd and solaris
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • Emit `days_remaining` performance data

    Emit `days_remaining` performance data

    The question will be whether this applies to any monitored certificate or only the leaf certificate.

    Emitting metrics for the specific chain position likely won't be useful, so I'm leaning towards making the assumption that days_remaining (or whatever name is settled on) will be for the certificate in chain position 0.

    We could also apply a restriction that the certificate in chain position 0 be a leaf certificate, but that seems fragile.

  • Generate RPM/DEB packages using nFPM

    Generate RPM/DEB packages using nFPM

    Overview

    The initial implementation won't include package signing or overall package niceties, but will hopefully still be useful.

    Goals:

    • apply SELinux context observed in RHEL environments
      • via postinstall script as nFPM does not appear to support natively applying SELinux contexts
    • deploy plugin to standard locations
      • /usr/lib64/nagios/plugins/check_cert via RPM
      • /usr/lib/nagios/plugins/check_cert via DEB
    • deploy deploy CLI tools to /usr/local/bin
      • the goal is to help prevent overwriting any existing tooling in system locations

    To more easily support generating packages, some current build settings/choices may need to be adjusted:

    • drop version suffixes from files
      • lscert-v0.9.2-0-gbc90f7e-linux-amd64 becomes lscert-linux-amd64
      • lscert-linux-amd64 is deployed to the system as /usr/local/bin/lscert

    References

    • https://nfpm.goreleaser.com/configuration/
  • Add support for evaluating MSSQL certificates

    Add support for evaluating MSSQL certificates

    Based on light reading, this will require TDS support.

    It may be that the https://github.com/denisenkom/go-mssqldb package can provide the necessary hooks to get at the certificate chain used by the MSSQL instance.

Webserver I built to serve Infura endpoints. Deployable via k8s and AWS EKS. Load testable via k6 tooling, and montiorable via prometheus and grafana

Infura Web Server Welcome to my verion of the take home project. I've created a webserver written in go to serve Infura api data over 3 possible data

Nov 15, 2022
cloud infra tooling for lnd provisioning/unlocking

lndinit: a wallet initializer utility for lnd This repository contains the source for the lndinit command. The main purpose of lndinit is to help auto

Dec 28, 2022
A dead simple tool to sign files and verify digital signatures.

minisign minisign is a dead simple tool to sign files and verify signatures. $ minisign -G

Dec 16, 2022
Sign, verify, encrypt and decrypt data with GPG in your browser.
Sign, verify, encrypt and decrypt data with GPG in your browser.

keygaen Sign, verify, encrypt and decrypt data with GPG in your browser. ⚠️ keygaen has not yet been audited! While we try to make keygaen as secure a

Nov 22, 2022
Signature-server - stores transaction blobs and uses predefined secret key to sign and verify those transactions

Signature Server Signature server stores transaction blobs and uses predefined s

Feb 14, 2022
A phoenix Chain client based on the go-ethereum fork,the new PoA consensus engine is based on the VRF algorithm.

Phoenix Official Golang implementation of the Phoenix protocol. !!!The current version is for testing and developing purposes only!!! Building the sou

Apr 28, 2022
Huobi Eco Chain client based on the go-ethereum fork

The Huobi Open Platform is a unified infrastructure platform based on the technical, traffic and ecological resources of the Huobi Group, and will be gradually open to the blockchain industry.

Dec 31, 2022
A fast and lightweight interactive terminal based UI application for tracking cryptocurrencies 🚀
A fast and lightweight interactive terminal based UI application for tracking cryptocurrencies 🚀

cointop is a fast and lightweight interactive terminal based UI application for tracking and monitoring cryptocurrency coin stats in real-time.

Jan 6, 2023
Yet another Binance Smart Chain client based on TrustFi Network

TrustFi Smart Chain The goal of TrustFi Smart Chain is to bring programmability and interoperability to Binance Chain. In order to embrace the existin

Mar 27, 2021
CLI Tool to remove unwanted connections from your Chia Node based on Geo IP Location.

chia-bouncer Tiny CLI tool to remove unwanted connections from your Chia Node based on the Geo IP Location (Country). The Tool is written in golang an

Jun 25, 2021
SwissWallet is a deterministic cryptocurrency wallet generator heavily based on MindWallet and MemWallet

SwissWallet SwissWallet is a deterministic cryptocurrency wallet generator heavily based on MindWallet and MemWallet but using argon2 and scrypt by de

Jul 28, 2022
The Fabric Smart Client is a new Fabric Client that lets you focus on the business processes and simplifies the development of Fabric-based distributed application.

Fabric Smart Client The Fabric Smart Client (FSC, for short) is a new Fabric client-side component whose objective is twofold. FSC aims to simplify th

Dec 14, 2022
Akroma GO client - Akroma is an EVM based application development platform (smart-contracts).

Akroma Akroma is an EVM based application development platform (smart-contracts). Akroma will utilize a Masternode system, and build out an Oracle pla

Dec 11, 2022
An easy to setup local crypto wallet based on Geth

CryptoWallet An easy to setup local crypto wallet based on Geth To run. go run CrytoWallet This will expose a set a api's. To Create new Wallet curl

Oct 15, 2021
A work-in-progress Bitcoin wallet based on Output Descriptors

go-wallet A work-in-progress Bitcoin wallet Descriptors go-wallet is designed around Bitcoin Descriptors. It implements a Output Script Descriptors la

May 4, 2022
Sharespot based Fisco
Sharespot based Fisco

ShareSpot区块链开放式网络共享 一个基于FISCO BCOS区块链网络的无线网络资源共享平台 FISCO BCOS是由国内企业主导研发、对外开源、安全可控的企业级金融联盟链底层平台,由金链盟开源工作组协作打造,并于2017年正式对外开源。 ShareSpot最初由东南大学移动通信国家重点实验

Dec 8, 2021
An application based on fabric Hyperledger

An application based on fabric Hyperledger

Oct 31, 2021
Simple, fast and safe cross-platform linear binary stream communication protocol. AES key exchange based on ecc secp256k1

FFAX Protocol 2 dev 简体中文 Welcome to FFAX Protocol v2 Quick start go get github.com/RealFax/FFAX func example() { listener, err := net.Listen("tcp",

Mar 21, 2022
A Binance Smart Chain client based on the go-ethereum fork

A Binance Smart Chain client based on the go-ethereum fork

Dec 31, 2022