#!/usr/bin/env bash # # JbTecWiz Support Centre -- generated fix script # # Fault : "x509: certificate has expired or is not yet valid" / SSL certificate problem # Fix : Inspect the chain and refresh the CA bundle # Source: https://jbtecwiz.com/support/lnx-cert-expired # # Run as : Shell as root # Expect : 25 minutes # Risk : low # Reversible : yes # # WHEN THIS IS THE RIGHT FIX # The clock is right. Find out which certificate is actually the problem # before changing anything. # # HOW TO UNDO IT # Remove the certificate from /usr/local/share/ca-certificates and # re-run update-ca-certificates. # # Walks the fix one step at a time and asks before each. Steps with no # command are yours to do -- it prints those and waits. DRYRUN=1 prints # without executing; UNATTENDED=1 does not ask. # # -------------------------------------------------------------------- # NO WARRANTY - USE AT YOUR OWN RISK # # This script is provided by JbTecWiz as-is and with no warranty of any # kind, express or implied. You run it entirely at your own risk. # # JbTecWiz accepts no liability for any loss or damage arising from its # use, including but not limited to data loss, downtime, or configuration # changes that turn out to be wrong for your system. # # You are responsible for reading this script before running it, for # satisfying yourself that it suits the machine in front of you, and for # having a working backup first. Some steps cannot be undone. # -------------------------------------------------------------------- set -uo pipefail DRYRUN="${DRYRUN:-0}" UNATTENDED="${UNATTENDED:-0}" failed=0 # - THIS SCRIPT WILL NOT RUN UNTIL YOU EDIT IT - cat >&2 <<'EOF' This script needs editing before it can run. Replace each of these with a real value: example.com (a placeholder domain) Then delete this block near the top of the script. EOF exit 2 if [ "$(id -u)" -ne 0 ]; then echo " This fix is documented as needing root. Re-run with sudo." >&2 exit 3 fi rule() { printf "\n%s\n" "$(printf '-%.0s' $(seq 1 70))"; if [ $# -gt 0 ]; then echo "$1"; fi; } prose() { echo "$1" | fold -s -w 74 | sed "s/^/ /"; } # Returns 0 when the caller should run the command, 1 when it should not. # A manual step always returns 1 -- there is nothing for the caller to run. step() { # step [command lines...] local n="$1" dotext="$2" why="$3" mode="$4"; shift 4 rule " Step $n of 6" prose "$dotext" if [ -n "$why" ]; then echo; prose "$why"; fi if [ "$mode" = "manual" ]; then echo; echo " -> Do this yourself, then press Enter to carry on." if [ "$UNATTENDED" = "0" ] && [ "$DRYRUN" = "0" ]; then read -r _; fi return 1 fi echo; printf " %s\n" "$@"; echo if [ "$DRYRUN" = "1" ]; then echo " (dry run -- not executed)"; return 1; fi if [ "$UNATTENDED" = "0" ]; then read -r -p " Run this step? [Y]es / [S]kip / [Q]uit " a case "$a" in [Qq]*) echo " Stopped at your request."; exit 0 ;; [Ss]*) echo " Skipped."; return 1 ;; esac fi return 0 } rule echo " "x509: certificate has expired or is not yet valid" / SSL certificate problem" echo " Inspect the chain and refresh the CA bundle" echo echo " Risk: low Reversible 25 minutes" echo prose 'No warranty. Use at your own risk - JbTecWiz accepts no liability. Read it before you run it, and have a backup.' rule echo if [ "$UNATTENDED" = "0" ] && [ "$DRYRUN" = "0" ]; then read -r -p " Ready? [y/N] " go case "$go" in [Yy]*) ;; *) echo " Nothing was changed."; exit 0;; esac fi if step 1 'Read the chain the server presents and every certificate'\''s validity window.' '' cmd 'echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates'; then echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 1 failed. The rest of the fix may depend on it." >&2 fi fi if step 2 'See the full chain, which is where a missing or expired intermediate shows up.' '"unable to get local issuer certificate" almost always means the server is not sending its intermediate, not that your trust store is wrong. That is the server operator'\''s bug.' cmd 'echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null | grep -E '\''s:|i:'\'''; then echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null | grep -E 's:|i:' if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 2 failed. The rest of the fix may depend on it." >&2 fi fi if step 3 'Update the trust store -- an old bundle is the other common cause.' '' cmd 'sudo apt-get update && sudo apt-get install --only-upgrade ca-certificates && sudo update-ca-certificates'; then sudo apt-get update && sudo apt-get install --only-upgrade ca-certificates && sudo update-ca-certificates if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 3 failed. The rest of the fix may depend on it." >&2 fi fi if step 4 'On RHEL-family the commands differ.' '' cmd 'sudo dnf upgrade ca-certificates && sudo update-ca-trust extract'; then sudo dnf upgrade ca-certificates && sudo update-ca-trust extract if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 4 failed. The rest of the fix may depend on it." >&2 fi fi if step 5 'To trust an internal CA, install its root properly rather than disabling verification.' 'curl -k and GIT_SSL_NO_VERIFY make the error disappear by switching off the check that was protecting you. They are for one-off diagnosis, never for a fix.' cmd 'sudo cp internal-ca.crt /usr/local/share/ca-certificates/' 'sudo update-ca-certificates'; then sudo cp internal-ca.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 5 failed. The rest of the fix may depend on it." >&2 fi fi if step 6 'Verify against the store explicitly.' '' cmd 'openssl verify -CApath /etc/ssl/certs <(echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509)'; then openssl verify -CApath /etc/ssl/certs <(echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509) if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 6 failed. The rest of the fix may depend on it." >&2 fi fi rule " Confirm it worked" prose 'curl succeeds without -k.' if [ "$DRYRUN" = "0" ]; then curl -sS -o /dev/null -w '%{http_code}\n' https://example.com fi rule if [ "$failed" -gt 0 ]; then echo " Finished with $failed failed step(s)." echo " Read the full write-up at https://jbtecwiz.com/support/lnx-cert-expired" else echo " Finished." fi echo prose 'To undo: Remove the certificate from /usr/local/share/ca-certificates and re-run update-ca-certificates.' rule