Check a PEM certificate’s expiration date

Read notAfter with OpenSSL, test an expiration threshold, inspect certificate bundles, and calculate remaining days with explicit error handling.

Best practices
Secure network connections and certificate management

Use openssl x509 -in certificate.pem -noout -dates to print a certificate's validity period. notBefore is its start time and notAfter is its expiration time, normally displayed in GMT. For an automated threshold check, use -checkend rather than parsing a date string.

Read the dates

openssl x509 -in certificate.pem -noout -dates
# Example output:
# notBefore=Mar 20 12:00:00 2023 GMT
# notAfter=Mar 20 12:00:00 2024 GMT

# Print only the expiration date.
openssl x509 -in certificate.pem -noout -enddate

The example dates are illustrative, not a currently valid certificate.

Test a renewal threshold

# 30 days = 2,592,000 seconds.
if openssl x509 -in cert.pem -checkend 2592000 -noout; then
  echo "Certificate expires beyond the 30-day threshold."
else
  echo "Certificate expires within 30 days, or it could not be read. Check diagnostics."
fi

For a successfully parsed certificate, exit status zero means it will not expire within the threshold. A nonzero status can mean expiration or a read/parse error, so retain the diagnostic output. This check does not validate the hostname, trust chain, or notBefore date.

Inspect a directory

for f in /etc/ssl/certs/*.pem; do
  [ -f "$f" ] || continue
  if exp=$(openssl x509 -in "$f" -noout -enddate); then
    printf '%s -> %s\n' "$f" "$exp"
  else
    printf 'Could not read certificate: %s\n' "$f" >&2
  fi
done

Keep the system clock accurate before comparing dates. Convert GMT to local time explicitly when reporting results to others.

A full-chain PEM contains several certificates. openssl x509 reads the first certificate, normally the leaf in a correctly ordered server chain. To inspect all certificates, including intermediates:

openssl crl2pkcs7 -nocrl -certfile fullchain.pem \
  | openssl pkcs7 -print_certs -noout -text

Inspect a remote endpoint

openssl s_client -servername example.com -connect example.com:443 </dev/null \
  | openssl x509 -noout -dates

This extracts dates; it does not by itself prove the endpoint's identity. Use explicit hostname and trust verification for that separate task. When an endpoint has renewed, check what it serves rather than assuming it loaded the new file.

Guance SSL tests can check certificate lifetime by hostname and port. Include every relevant entry point and select a remaining-days condition appropriate to the renewal schedule.

Common questions

Does this work when the PEM also contains a private key?

Yes. openssl x509 reads a certificate block and skips other PEM block types. It does not print the private key.

How can I print remaining days?

This shell example requires GNU date, commonly available on Linux; macOS's default date has different options:

end=$(openssl x509 -in cert.pem -noout -enddate) || exit 1
end_epoch=$(date -d "${end#notAfter=}" +%s) || exit 1
now_epoch=$(date +%s) || exit 1
printf '%s days\n' "$(( (end_epoch - now_epoch) / 86400 ))"

Integer division truncates toward zero, so use -checkend for threshold decisions rather than treating this rounded display as a precise pass/fail result.

Does a future notAfter date mean the certificate is valid?

It only answers the expiration question. A certificate can still be not yet valid, issued for another hostname, untrusted, revoked, or paired with the wrong key.

See the OpenSSL x509 options.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting