From aae90bf5ae46cfa2844446c8cd55f671b64b2a01 Mon Sep 17 00:00:00 2001 From: catchdave <823598+catchdave@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:58:40 -0800 Subject: [PATCH] Create find_all_certs.sh Finds all certs on a synology --- find_all_certs.sh | 227 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 find_all_certs.sh diff --git a/find_all_certs.sh b/find_all_certs.sh new file mode 100644 index 0000000..9abc8c5 --- /dev/null +++ b/find_all_certs.sh @@ -0,0 +1,227 @@ +#!/bin/bash +# +# Finds all .pem certs on synology under /usr. +# +# Usage: ./find_all_certs.sh [--valid-only | --invalid-only] +# --valid-only - Only show valid certificates found +# --invalid-only - Only show invalid certificates found +# --no-color - Don't display ANSII Color output + +if [ "$EUID" -ne 0 ]; then + echo "This script must be run as root or with sudo." + exit 1 +fi + +# Color codes +GREEN="\033[1;32m" +RED="\033[0;31m" +YELLOW="\033[0;33m" +BLUE="\033[0;95m" +NC="\033[0m" # No Color +BOLD="\033[1m" +HEAD_COL="\033[0;97m\033[0;100m" + +# Initialize variables +NOW_TS=$(date +%s) +BASE_DIR=/usr/ +WARNINGS=() +PREV_DIR="" +valid_count=0 +count=0 +total_count=0 +total_valid=0 +total_invalid=0 +total_dirs_no_valid=0 +total_dirs=0 +valid_status= +mode=all +color=1 + +main() { + parse_args "$@" + + print_header + while read -r cert; do + cert_dir=$(dirname "$cert") + cert_file=$(basename "$cert") + + if parse_cert_info "$cert"; then # Sets vars: $from, $to, $subject, $issuer, $validity_color & $valid_status + process_dir_change "$cert_dir" "$cert_file" + ((count++)) + ((total_count++)) + + check_filter "$valid_status" || continue + print_cert_line "$validity_color" "$cert_file" "$from" "$to" "$subject" "$issuer" "$valid_status" + fi + done < <(find "$BASE_DIR" -type f -name "*.pem" -not -path "/volume*" 2>/dev/null) + + printf "$(get_line_format "\u2517" "\u2537" "\u251B")" | sed 's/ /━/g' + print_summary +} + +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + --no-color) + color=0 + shift + ;; + --valid-only) + mode=valid_only + shift + ;; + --invalid-only) + mode=invalid_only + shift + ;; + *) + echo "Usage: $0 [--valid-only | --invalid-only] [--no-color]" + exit 1 + ;; + esac + done + + if [[ "$color" == "0" ]]; then + GREEN= + RED= + YELLOW= + BLUE= + NC= + BOLD= + HEAD_COL= + fi +} + +get_line_format() { + local start=$1 + local mid=$2 + local end=$3 + local color_line="${4:-}" + local color_status="${5:-}" + + local line_format="__START__LINE_COLOR %-44s __MID__ STATUS_COLOR%-28s${NC}LINE_COLOR __MID__ \ +STATUS_COLOR%-28s${NC}LINE_COLOR __MID__ %-20s __MID__ %-20s __MID__ STATUS_COLOR%-7s ${NC}__END__\n" + line_format="${line_format//__START__/${start}}" + line_format="${line_format//__MID__/${mid}}" + line_format="${line_format//__END__/${end}}" + + line_format="${line_format//STATUS_COLOR/${color_status}}" + line_format="${line_format//LINE_COLOR/${color_line}}" + + echo "$line_format" +} + +# Skip files that are not valid certificates +check_valid_cert() { + local cert=$1 + if [[ "$(head -n 1 "$cert")" != "-----BEGIN CERTIFICATE-----" ]]; then + return 1 + fi + return 0 +} + +# Execute filtering based on mode +check_filter() { + local valid_status=$1 + if [[ "$mode" == "valid_only" && "$valid_status" != "active" ]]; then + return 1 + elif [[ "$mode" == "invalid_only" && "$valid_status" == "active" ]]; then + return 1 + fi + return 0 +} + + +print_cert_line() { + printf "$(get_line_format "\u2503" "\u2502" "\u2503" "" "$1")" "$2" "$3" "$4" "$5" "$6" "$7" +} + +print_dir_warn() { + if [[ "${count:-0}" -ne 0 && "${valid_count:-0}" -eq 0 ]]; then + WARNINGS+=("$(echo -e "${RED}${BOLD}[WARN] No Valid Certs in: ${NC}${RED}$1/${NC}")") + ((total_dirs_no_valid++)) + fi +} + +print_header() { + printf "$(get_line_format "\u250F" "\u252F" "\u2513")" | sed 's/ /\xE2\x94\x81/g' + printf "$(get_line_format "\u2503" "\u2502" "\u2503" "${HEAD_COL}")" "Filename" "Valid From" "Valid To" "Domain" "Issuer" "Status" +} + +process_dir_change() { + local cert_dir="$1" + local cert_file="$2" + + if [[ "$cert_dir" == "$PREV_DIR" ]]; then + return + fi + + print_dir_warn "$PREV_DIR" + ((total_dirs++)) + + valid_count=0 + count=0 + PREV_DIR="$cert_dir" + + printf "$(get_line_format "\u2520" "\u2534" "\u2528")" | sed 's/ /─/g' + printf "\u2503 ${BLUE}%-162s${NC} \u2503\n" "$cert_dir" + printf "$(get_line_format "\u2520" "\u252C" "\u2528")" | sed 's/ /─/g' +} + +print_summary() { + local line_format="${HEAD_COL}\u2503 ${BOLD}%-28s${NC}${HEAD_COL} \u2502 %-4s \u2503${NC}\n" + + echo "" + printf "%s\n" "${WARNINGS[@]}" + echo "" + echo -e "${HEAD_COL}${BOLD}===== Summary =====${NC}" + printf "${HEAD_COL}\u250F%37s\u2513${NC}\n" | sed 's/ /\xE2\x94\x81/g' + printf "$line_format" "Total Directories" "$total_dirs" + printf "$line_format" "Total Certificates" "$total_count" + printf "$line_format" "Total Dirs w/ no valid cert" "$total_dirs_no_valid" + printf "$line_format" "Total Valid Certs" "$total_valid" + printf "$line_format" "Total InValid Certs" "$total_invalid" + printf "${HEAD_COL}\u2517%37s\u251B${NC}\n" | sed 's/ /\xE2\x94\x81/g' +} + +# Parses info from a SSL cert, extracting domain, issuer and dates. Provides time validity and appropriate color for validity status. +parse_cert_info() { + local cert="$1" + local cert_info + + # Parse details from cert_info + cert_info=$(openssl x509 -in "$cert" -noout -subject -issuer -startdate -enddate 2>/dev/null) + if [[ $? -ne 0 ]]; then + return 1 + fi + subject=$(echo "$cert_info" | sed -n '/^subject=/s/.*[Cc][Nn][ ]*=[ ]*\([^,]*\).*/\1/p') + issuer=$(echo "$cert_info" | sed -n '/^issuer=/s/.*[Oo][ ]*=[ ]*\([^,]*\).*/\1/p') + from=$(echo "$cert_info" | sed -n 's/^notBefore=//p') + to=$(echo "$cert_info" | sed -n 's/^notAfter=//p') + + # Convert dates to Unix timestamps for comparison + local from_ts=$(date -d "$from" +%s) + local to_ts=$(date -d "$to" +%s) + + # Determine validity of certs + valid_status="invalid" + if (( from_ts > NOW_TS )); then + validity_color=$YELLOW # Not reached + valid_status="future" + ((total_invalid++)) + elif (( to_ts < NOW_TS )); then + validity_color=$RED # Expired + valid_status="expired" + ((total_invalid++)) + else + validity_color=$GREEN # Current + valid_status="active" + ((valid_count++)) + ((total_valid++)) + fi + + return 0 +} + +### Run main program ### +main "$@"