From 7c4cacc6bb3a057cab174a9450268175ea139c9d Mon Sep 17 00:00:00 2001 From: Gilles Mouchet Date: Sun, 26 Apr 2026 20:44:39 +0200 Subject: [PATCH] dev #20260426 --- bin/create-ca.sh | 15 +- bin/generate-cert.sh | 427 ++++++++++++------------- bin/info-cert.sh | 258 +++++++++++++++ bin/install.sh | 185 +++++------ bin/random-cert.sh | 161 ++++++++++ bin/remove-cert.sh | 110 +++++++ bin/renew-cert.sh | 136 ++++++++ config/ca-config | 102 ++++++ config/default.conf | 25 +- config/own-pki.conf | 30 +- lib/.gitkeep | 0 lib/{check-rc.sh => check-rc.sh-old} | 2 +- lib/core.sh | 86 ++++- lib/expired-date.sh | 55 ++++ lib/{set-color.sh => set-color.sh-old} | 4 +- lib/stdlib.sh | 7 +- lib/{yes-no.sh => yes-no.sh-old} | 0 17 files changed, 1237 insertions(+), 366 deletions(-) create mode 100755 bin/info-cert.sh create mode 100755 bin/random-cert.sh create mode 100755 bin/remove-cert.sh create mode 100755 bin/renew-cert.sh create mode 100644 config/ca-config delete mode 100644 lib/.gitkeep rename lib/{check-rc.sh => check-rc.sh-old} (70%) create mode 100644 lib/expired-date.sh rename lib/{set-color.sh => set-color.sh-old} (88%) rename lib/{yes-no.sh => yes-no.sh-old} (100%) diff --git a/bin/create-ca.sh b/bin/create-ca.sh index 123983b..e78b381 100755 --- a/bin/create-ca.sh +++ b/bin/create-ca.sh @@ -32,13 +32,13 @@ usage() { Usage: ./$(basename "$0") -n Template script Options: - -n, --common-name - CA common name [mandatory] + -n, --cn - CA common name [mandatory] -h, --help - show this help -v, --version - show script version Examples: - Show this help - ./$(basename "$0") -n "GMOLab CA" + Create CA called "GMOLab CA" + ./$(basename "$0") -n "GMOLab CA" EOF } @@ -90,7 +90,7 @@ $(basename "$0") $version Copyright (C) 2003 - $(date +%Y) Gilles Mouchet EOF exit ;; - *|help|-h|--help) + *|-h|--help) usage exit ;; @@ -120,9 +120,11 @@ Email address: ${ORANGE}%s${NC} ${RED}IMPORTANT${NC} You will be asked for a password. Choose a ${RED}STRONG PASSWORD${NC} and KEEP IT SECURE. - + You will be asked for it when creating certificates. - + +For automation, save the password in /root/.cred (KEY_CA_PASS=password). + " "${KEY_CA_PATH}/${CA_NAME}" "${CRT_CA_PATH}/${CA_NAME}" \ "$COUNTRY_NAME" "$STATE_OR_PROVINCE_NAME" "$LOCALITY_NAME" \ "$ORGANIZATION_NAME" "$ORGANIZATIONAL_UNIT_NAME" "$COMMON_NAME" "$EMAIL_ADDRESS" @@ -131,7 +133,6 @@ You will be asked for it when creating certificates. # check if CA files exist if [ -f "$KEY_CA_PATH/$CA_NAME.key" ]; then - #echo -e "${RED}\n$KEY_CA_PATH/$CA_NAME.key already exists!\n" msg_warn "\n$KEY_CA_PATH/$CA_NAME.key already exists!\n" yes_no "Are you sure you want to delete it" fi diff --git a/bin/generate-cert.sh b/bin/generate-cert.sh index 7dbd1d9..99a64c7 100755 --- a/bin/generate-cert.sh +++ b/bin/generate-cert.sh @@ -37,7 +37,7 @@ Usage: $0 -c -k -n [-d ] [-i - ca name (./info-cert.sh -c get list of CA name) - -n, --commonName - common name (server.domain.ext) + -n, --commonName - common name fqdn format (server.domain.ext) -d, --dns - subject alternative name (multiple SAN separated by commas) -i, --ip - ip address to add to the certificate (multiple IPs separated by commas) -t, --days - validity period of the certificate in days (defaults $days days) @@ -46,14 +46,12 @@ Options: -v, --version - show script version Examples: - Generate a certificate for myweb.gmolab.net - ./$(basename "$0") -c gmolab_ca -n myweb.gmolab.net + Generate a certificate for myweb.gmolab.net + ./$(basename "$0") -c gmolab_ca -n myweb.gmolab.net - Generate a certifciate for myweb.gmolab.net with dns alias and ip - ./$(basename "$0") -c gmolab_ca -n myweb.gmolab.net -i 92.168.1.10,10.0.0.5,10.10.34.25 --dns www.gmolab.net,qual-myweb.gmolab.net -t 49 + Generate a certifciate for myweb.gmolab.net with dns alias and ip + ./$(basename "$0") -c gmolab_ca -n myweb.gmolab.net -i 92.168.1.10,10.0.0.5,10.10.34.25 --dns www.gmolab.net,qual-myweb.gmolab.net -t 49 - Show this help - ./$(basename "$0") -h EOF } @@ -88,163 +86,151 @@ fi set_color # parse cli parameters -while [[ "$#" -gt 0 ]]; do - case "$1" in - -c|--ca-name) - if [[ -z "$2" || "$2" == -* ]]; then - msg_error "\nError: Argument missing for option -c or --ca-name.\n" - usage - exit 1 - else - CA_CRT=$2.crt - CA_KEY=$2.key - fi - shift 2 - ;; - -n|--common-name) - if [[ -z "$2" || "$2" == -* ]]; then - msg_error "\nError: Argument missing for option -n or --common-name.\n" - usage - exit 1 - else - if [[ ! $2 =~ ^([a-z0-9]+(-[a-z0-9]+)*\.){2,}[a-z]{2,}$ ]]; then - msg_error "\n$2 is not a commonName valid.\n" + while [[ "$#" -gt 0 ]]; do + case "$1" in + -c|--ca-name) + if [[ -z "$2" || "$2" == -* ]]; then + msg_error "\nError: Argument missing for option -c or --ca-name.\n" usage exit 1 else + CA_CRT=$2.crt + CA_KEY=$2.key + fi + shift 2 + ;; + -n|--cn) + if [[ -z "$2" || "$2" == -* ]]; then + msg_error "\nError: Argument missing for option -n or --cn.\n" + usage + exit 1 + else + check_format_fqdn "$2" COMMON_NAME=$2 # record for db if no option -d or --dns exist. # some browser needed the commName in Subject Alternative Name DNS_LINE=$2 # record for db if no option -d or --dns exist. Some browser needed the commName in Subject Alternative Name + fi - fi - shift 2 - ;; - -d|--dns) - if [[ -z "$2" || "$2" == -* ]]; then - msg_error "\nError: Argument missing for option -d or --dns.\n" - usage - exit 1 - else - # add commonName and parameters -d --dns value in dnsLine variable. - # some browser needed the commName in Subject Alternative Name - DNS_LINE="$COMMON_NAME,$2" - - # put dnsLine value in dns array - IFS=',' read -r -a DNS <<< "$DNS_LINE" - - # check dns format - for SAN_DNS in "${DNS[@]}"; do - if [[ ! $SAN_DNS =~ ^([a-z0-9]+(-[a-z0-9]+)*\.){2,}[a-z]{2,}$ ]]; then - msg_error "\n$SAN_DNS is not a commonName valid.\n" - exit 1 - fi - done - fi - shift 2 - ;; - -i|--ip) - if [[ -z "$2" || "$2" == -* ]]; then - msg_error "\nError: Argument missing for option -i or --ip.\n" - usage - exit 1 - else - # add parameters -i --ip values in IP_LINE variable. - IP_LINE=$2 - # put ipLine value in ipAddrs array - IFS=',' read -r -a IP_ADDRS <<< "$2" - - # check ip format - for SAN_IP in "${IP_ADDRS[@]}"; do - if [[ ! $SAN_IP =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]; then - msg_error "\n$SAN_IP is not an address IP valid.\n" - exit 1 - fi - done - fi - shift 2 - ;; - -t|--days) - if [[ -z "$2" || "$2" == -* ]]; then - msg_err "\nError: Argument missing for option -t or --days.\n" - usage - exit 1 - else - DAYS=$2 - fi - shift 2 - ;; - -y|--assumeyes) - ASSUME_YES="1" - shift - ;; - -v|--version) - cat << EOF + shift 2 + ;; + -d|--dns) + if [[ -z "$2" || "$2" == -* ]]; then + msg_error "\nError: Argument missing for option -d or --dns.\n" + usage + exit 1 + else + # add commonName and parameters -d --dns value in dnsLine variable. + # some browser needed the commName in Subject Alternative Name + DNS_LINE="$COMMON_NAME,$2" + + # put dnsLine value in dns array + IFS=',' read -r -a DNS <<< "$DNS_LINE" + + # check dns format + for SAN_DNS in "${DNS[@]}"; do + check_format_fqdn $SAN_DNS + done + fi + shift 2 + ;; + -i|--ip) + if [[ -z "$2" || "$2" == -* ]]; then + msg_error "\nError: Argument missing for option -i or --ip.\n" + usage + exit 1 + else + # add parameters -i --ip values in IP_LINE variable. + IP_LINE=$2 + # put ipLine value in ipAddrs array + IFS=',' read -r -a IP_ADDRS <<< "$2" + + # check ip format + for SAN_IP in "${IP_ADDRS[@]}"; do + check_format_ip $SAN_IP + done + fi + shift 2 + ;; + -t|--days) + if [[ -z "$2" || "$2" == -* ]]; then + msg_err "\nError: Argument missing for option -t or --days.\n" + usage + exit 1 + else + DAYS=$2 + fi + shift 2 + ;; + -y|--assumeyes) + ASSUME_YES="1" + shift + ;; + -v|--version) + cat << EOF $(basename "$0") $version Copyright (C) 2003 - $(date +%Y) Gilles Mouchet EOF - exit - ;; - -h|--help) - usage - exit - ;; - esac -done - -# if array dns is empty we add commonName -if [ "${#DNS[@]}" -eq 0 ]; then - DNS+="$COMMON_NAME" -fi - -# check if mandatory variables exists -if [[ -z "$CA_CRT" || -z "$CA_KEY" || -z "$COMMON_NAME" ]]; then - usage - exit 1 -fi - -# check if ca key and ca crt file exist -if [[ ! -f "$CRT_CA_PATH/$CA_CRT" || ! -f "$KEY_CA_PATH/$CA_KEY" ]]; then - msg_error "One or both of the following files are missing:" - msg_warn " - $CRT_CA_PATH/$CA_CRT" - msg_warn " - $KEY_CA_PATH/$CA_KEY" - exit 1 -fi -# summary -printf " + exit + ;; + *|-h|--help) + usage + exit + ;; + esac + done + + # check if file doesn't exists + if [ -f "$CERTS_PATH/$COMMON_NAME.key" ]; then + echo -e "The ${ORANGE}$CERTS_PATH/$COMMON_NAME.key${NC} file exists!" + yes_no "Are you sure you want to continue" + fi + + # if array dns is empty we add commonName + if [ "${#DNS[@]}" -eq 0 ]; then + DNS+="$COMMON_NAME" + fi + + # check if mandatory variables exists + if [[ -z "$CA_CRT" || -z "$CA_KEY" || -z "$COMMON_NAME" ]]; then + usage + exit 1 + fi + + # check if ca key and ca crt file exist + if [[ ! -f "$CRT_CA_PATH/$CA_CRT" || ! -f "$KEY_CA_PATH/$CA_KEY" ]]; then + msg_error "One or both of the following files are missing:" + msg_warn " - $CRT_CA_PATH/$CA_CRT" + msg_warn " - $KEY_CA_PATH/$CA_KEY" + exit 1 + fi + # summary + printf " ${CYAN}Summary ---------------------------------------------------------------------${NC} Certifcate authority: ${GREEN}%s${NC} Common name: ${GREEN}%s${NC} " "$CRT_CA_PATH/$CA_CRT" "$COMMON_NAME" + + echo -e "SAN List:" + for SAN_DNS in "${DNS[@]}"; do + msg_ok " - $SAN_DNS" + done + + echo -e "IP List:" + for SAN_IP in "${IP_ADDRS[@]}"; do + msg_ok " - $SAN_IP" + done + + echo -e "Validity:" + echo -e " Not before: ${GREEN}$(date +"%b %d %H:%M:%S %Y GMT")${NC}" + echo -e " Not After : ${GREEN}$(date -u -d "+$DAYS days" +"%b %d %H:%M:%S %Y GMT")${NC}" + + if [ "$ASSUME_YES" == "0" ]; then + yes_no "Is it ok" + fi -echo -e "SAN List:" -for SAN_DNS in "${DNS[@]}"; do - msg_ok " - $SAN_DNS" -done - -echo -e "IP List:" -for SAN_IP in "${IP_ADDRS[@]}"; do - msg_ok " - $SAN_IP" -done - -echo -e "Validity:" -echo -e " Not before: ${GREEN}$(date +"%b %d %H:%M:%S %Y GMT")${NC}" -echo -e " Not After : ${GREEN}$(date -u -d "+$DAYS days" +"%b %d %H:%M:%S %Y GMT")${NC}" - -if [ "$ASSUME_YES" == "0" ]; then - yes_no "Is it ok" -fi - - - -# create destination path -if [ ! -d "$CERTS_TMP_PATH" ]; then - echo "create $CERTS_TMP_PATH" - mkdir -p $CERTS_TMP_PATH -fi - -echo -e "\nPrepare the openSSL configuration file" -cat > "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" << EOF + echo -e "\nPrepare the openSSL configuration file" + cat > "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" << EOF [ req ] default_bits = 2048 distinguished_name = req_distinguished_name @@ -260,83 +246,86 @@ subjectAltName = @alt_names [ alt_names ] EOF -echo -e " Add SAN" + echo -e " Add SAN" # add dns -i=1 -#echo "DNS.$i = ${COMMON_NAME}" >> "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" -#((i++)) -for SAN_DNS in "${DNS[@]}"; do - echo "DNS.$i = $AN_DNS" >> "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" - ((i++)) -done - -echo -e " Add IP" -# add ip -i=1 -for SAN_IP in "${IP_ADDRS[@]}"; do - echo "IP.$i = $SAN_IP" >> "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" - ((i++)) -done - -# create certificate -echo -e "Generating the private key..." -openssl genrsa -out "${CERTS_TMP_PATH}/${COMMON_NAME}.key" 4096 - -echo -e "Generating csr file..." -openssl req -new -key "${CERTS_TMP_PATH}/${COMMON_NAME}.key" -out "${CERTS_TMP_PATH}/${COMMON_NAME}.csr" -config "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" - -echo -e "Signing the certificate with the CA..." -openssl x509 -req -in "${CERTS_TMP_PATH}/${COMMON_NAME}.csr" \ - -CA "$CRT_CA_PATH/$CA_CRT" -CAkey "$KEY_CA_PATH/$CA_KEY" -CAcreateserial \ - -out "${CERTS_TMP_PATH}/${COMMON_NAME}.crt" -days "$DAYS" \ - -extensions req_ext -extfile "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" \ - > /dev/null 2>&1 #-passin pass:pa55w0rd > /dev/null 2>&1 -echo -n "Result of certificate signing: " -check_rc $? -#echo -e "\nVerify certifcate" -#echo -e "\nValidity" -#openssl x509 -in $CERTS_TMP_PATH/${COMMON_NAME}.crt -noout -dates -#echo -e "\nSubject Alternative Name" -#openssl x509 -in $CERTS_TMP_PATH/${COMMON_NAME}.crt -noout -ext subjectAltName -echo -e -n "\nVerify the validity of ${GREEN}$CERTS_TMP_PATH/${COMMON_NAME}.crt${NC} using the trust chain: " -openssl verify -CAfile $CRT_CA_PATH/$CA_CRT $CERTS_TMP_PATH/$COMMON_NAME.crt > /dev/null 2>&1 -check_rc $? + i=1 + for SAN_DNS in "${DNS[@]}"; do + echo "DNS.$i = $SAN_DNS" >> "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" + ((i++)) + done + + echo -e " Add IP" + # add ip + i=1 + for SAN_IP in "${IP_ADDRS[@]}"; do + echo "IP.$i = $SAN_IP" >> "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" + ((i++)) + done + + # create certificate + echo -e "Generating the private key..." + openssl genrsa -out "${CERTS_PATH}/${COMMON_NAME}.key" 4096 + + echo -e "Generating csr file..." + openssl req -new -key "${CERTS_PATH}/${COMMON_NAME}.key" -out "${CERTS_PATH}/${COMMON_NAME}.csr" -config "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" + + echo -e "Signing the certificate with the CA..." + openssl x509 -req -in "${CERTS_PATH}/${COMMON_NAME}.csr" \ + -CA "$CRT_CA_PATH/$CA_CRT" -CAkey "$KEY_CA_PATH/$CA_KEY" -CAcreateserial \ + -out "${CERTS_PATH}/${COMMON_NAME}.crt" -days "$DAYS" \ + -extensions req_ext -extfile "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" \ + #-passin pass:$KEY_CA_PASS \ + > /dev/null 2>&1 + rc=$? + echo -n "Result of certificate signing: " + check_rc $rc + #echo -e "\nVerify certifcate" + #echo -e "\nValidity" + #openssl x509 -in $CERTS_PATH/${COMMON_NAME}.crt -noout -dates + #echo -e "\nSubject Alternative Name" + #openssl x509 -in $CERTS_PATH/${COMMON_NAME}.crt -noout -ext subjectAltName + echo -e -n "\nVerify the validity of ${GREEN}$CERTS_PATH/${COMMON_NAME}.crt${NC} using the trust chain: " + openssl verify -CAfile $CRT_CA_PATH/$CA_CRT $CERTS_PATH/$COMMON_NAME.crt > /dev/null 2>&1 + check_rc $? # get validity date -NOT_BEFORE=$(openssl x509 -noout -in $CERTS_TMP_PATH/${COMMON_NAME}.crt -startdate | cut -d'=' -f2) -NOT_AFTER=$(openssl x509 -noout -in $CERTS_TMP_PATH/${COMMON_NAME}.crt -enddate | cut -d'=' -f2) +#NOT_BEFORE=$(openssl x509 -noout -in $CERTS_PATH/${COMMON_NAME}.crt -startdate | cut -d'=' -f2) +#NOT_AFTER=$(openssl x509 -noout -in $CERTS_PATH/${COMMON_NAME}.crt -enddate | cut -d'=' -f2) # check if commonName already exist on db -echo -e -n "\nCheck if ${GREEN}${COMMON_NAME}${NC} exist in DB: " -recordExist=$(sqlite3 $DB_PATH "SELECT EXISTS(SELECT 1 FROM certs WHERE common_name='${COMMON_NAME}');") -check_rc $? +#echo -e -n "\nCheck if ${GREEN}${COMMON_NAME}${NC} exist in DB: " +#recordExist=$(sqlite3 $DB_PATH "SELECT EXISTS(SELECT 1 FROM certs WHERE common_name='${COMMON_NAME}');") +#check_rc $? -if [ "$recordExist" == "1" ]; then - echo -e -n "Update ${ORANGE}${COMMON_NAME}${NC} in DB: " - sqlite3 $DB_PATH < + List the certificates expiring in the next days + -i, --info + Display certificate info. You can use wirdcard * in pattern + -n, --cn + List all cn + -h, --help + Show this help + -v, --version + Show script version + +Examples: + List all CA name + ./$(basename "$0") --list-ca + + List all certs cn + ./$(basename "$0") --cn + + Show infos for certificates whose CN begins with 'doe' + ./$(basename "$0") -i "doe*" + + Show infos for certificates whose CN ends with 'doe' + ./$(basename "$0") -i "*doe" + + Show infos for certificates where CN contains 'doe' + ./$(basename "$0") -i "*doe*" + + Show infos for certificates where CN is 'www.gmolab.net' + ./$(basename "$0") -i www.gmolab.net + + List the certificates expiring in the next 10 days + ./$(basename "$0") -d 10 +EOF +} +#----------------------------------------------------------- +# Certificates info +cert_info() { +echo -e "Number of certificates : ${CYAN}${#certList[@]}${NC}" + for certFile in "${certList[@]}"; do + # extract informations from certificates + cname=$(openssl x509 -noout -subject -in $certFile | cut -d"=" -f3) + issuer=$(openssl x509 -noout -issuer -in $certFile | sed 's/^issuer=//') + notAfter=$(openssl x509 -noout -enddate -in $certFile | cut -d"=" -f2) + notBefore=$(openssl x509 -noout -startdate -in $certFile | cut -d"=" -f2) + + # extract Subject Alternative Name + san=$(openssl x509 -text -noout -in $certFile | \ + grep -A 1 "Subject Alternative Name" | tail -n 1 | \ + sed 's/,/\n/g' | \ + sed -E 's/^\s*(DNS:|IP:|IPAddress:|IP Address:)//g' | \ + sed 's/ //g') + + # extract SAN dns + dnsList=$(echo "$san" | grep -v '^[0-9.]*$') + dnsArray=() + while IFS= read -r line; do + [[ -n "$line" ]] && dnsArray+=("$line") + done <<< "$dnsList" + + # extract SAN ip + ipList=$(echo "$san" | grep -E '^[0-9.]+$') + ipArray=() + while IFS= read -r line; do + [[ -n "$line" ]] && ipArray+=("$line") + done <<< "$ipList" + + echo -e "\n******************************************************" + echo -e "CA name: ${CYAN}$cname${NC}" + echo -e "******************************************************" + echo "Subject Alternative Name" + echo -e " DNS:" + for san_dns in "${dnsArray[@]}"; do + echo -e " ${CYAN} - $san_dns${NC}" + done + + echo -e " IP:" + for san_ip in "${ipArray[@]}"; do + echo -e " ${CYAN} - $san_ip${NC}" + done + + echo -e "Not valid before: ${CYAN}$notBefore${NC}" + echo -e "Not valid after : ${CYAN}$notAfter${NC}" + echo -e "Issuer: ${CYAN}$issuer${NC}" + done +} + +############################################################ +# MAIN +############################################################ + +main(){ + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + ROOT_DIR="$(dirname "$SCRIPT_DIR")" + +# read library + source "$ROOT_DIR/lib/stdlib.sh" + +# init config + init_default + init_env + +# set color + set_color + +# check if script is run with sudo + check_sudo + +# check if param exist + if [ -z "$1" ]; then + usage + exit 1 + fi + +# set color + set_color + +# read cli parameters + while [[ "$#" -gt 0 ]]; do + case "$1" in + -a|--all) + certList=($CERTS_PATH/*.crt) + cert_info + shift + ;; + -c|--ca) + files=( $CRT_CA_PATH/*.crt ) + for f in "${files[@]}"; do + filename=$(basename "$f" .crt) + if [ "$filename" == "ca-bundle" ] || [ "$filename" == "ca-bundle.trust" ]; then + continue + else + echo "CA name: $filename" + fi + done + shift + ;; + -d|--expire-day) + if [[ -z "$2" || "$2" == -* ]]; then + echo -e "\n${RED}Error: Argument missing for option -d or --validity-date. See ./$(basename "$0") --help${NC}\n" + exit 1 + + # check if nbr days is numeric and > 1 and < $DAYS + elif [[ "$2" =~ ^[0-9]+$ ]] && [ "$2" -ge 1 ] && [ "$2" -le "$DAYS" ]; then + expired_date $2 + for certData in "${expireDate[@]}"; do + daysLeft=$(echo $certData | cut -d"|" -f1 ) + cn=$(echo $certData | cut -d"|" -f2 ) + expDate=$(echo $certData | cut -d"|" -f3 ) + if [ "$daysLeft" -le 0 ]; then + color="$RED!! EXPIRED CERTIFICATE ---> " + elif [ "$daysLeft" -le 5 ]; then + color="$RED" + elif [ "$daysLeft" -le 10 ]; then + color="$ORANGE" + else + color="$GREEN" + fi + echo -e "${color}$cn expires in $daysLeft days ($expDate)${NC}" + done + else + echo -e "\n${RED}The number of days must be between 1 and $days. See ./$(basename "$0") --help${NC}\n" + fi + shift 2 + ;; + -i|--info) + if [[ -z "$2" || "$2" == -* ]]; then + msg_error "\nError: Argument missing for option -i or --info.\n" + usage + exit 1 + else + # check if $2 is not a glob ("*tto*") + if [[ ! "$2" == *[*?\[]* ]]; then + # it's not a glob, we test if file existe + if [ -f "$CERTS_PATH/$2.crt" ]; then + certList=("$CERTS_PATH/$2.crt") + cert_info + else + certList=() + cert_info + fi + else + # it's a glob + # set - if no .crt → files=() (empty) + shopt -s nullglob + certList=("$CERTS_PATH"/$2.crt) + shopt -u nullglob + cert_info + fi + fi + shift 2 + ;; + -n|--cn) + i=0 + files=( $CERTS_PATH/*.crt ) + for f in "${files[@]}"; do + cn=$(basename "$f" .crt) + echo $cn + ((i++)) + done + echo -e "\nThere are ${ORANGE}$i${NC} certificates." + shift + ;; + -v|--version) + cat << EOF +$(basename "$0") $version (c) 1990 - $(date +%Y) by Gilles Mouchet + +This script is provided "as is", WITHOUT ANY WARRANTY OF ANY KIND. +Non-Commercial Use License – See LICENSE for details + +EOF + exit + ;; + *|-h|--help) + usage + exit + ;; + esac + done +} +main "$@" \ No newline at end of file diff --git a/bin/install.sh b/bin/install.sh index 56a3724..e020317 100755 --- a/bin/install.sh +++ b/bin/install.sh @@ -15,111 +15,69 @@ # [1.0.0] - 2026-04-12 # - Added # - create environment for cert -# - create DB # - Project initialization # - initialization by gilles.mouchet@gmail.com # ############################################################ # -set -Eeuo pipefail VERSION=1.0.0 -############################################################ -# FUNCTIONS -############################################################ -#----------------------------------------------------------- -# init db -init_db(){ - mkdir -p "$(dirname "$DB_PATH")" - sqlite3 $DB_PATH </dev/null; then - msg_error "Access denied: user $USER does not have sudo privileges or a password is required.." - exit 1 - fi + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + ROOT_DIR="$(dirname "$SCRIPT_DIR")" + COPY_CONF=true -# check if the effective user ID is 0 (root) - if [[ $EUID -ne 0 ]]; then - msg_error "\nThis script must be run as root or with sudo.\n" - exit 1 - fi +# read library + source "$ROOT_DIR/lib/stdlib.sh" + +# init config + init_default + +# set color + set_color + +# check if script is run with sudo + check_sudo -# install sqlite - echo -n -e "Install ${ORANGE}sqlite${NC}. Please wait...: " - dnf install sqlite -y > /dev/null 2>&1 - check_rc $? - -# create paths - echo -n -e "Create path $BIN_PATH: " - if [ ! -d "$BIN_PATH" ]; then +# read cli parameters + while [[ "$#" -gt 0 ]]; do + case "$1" in + --reload-conf) + init_env + COPY_CONF=false + shift + ;; + esac + done +# create paths for environment own-pki + echo -n -e "Create path $BIN_PATH/lib: " + if [ ! -d "$BIN_PATH/lib" ]; then mkdir -p "$BIN_PATH" 2>/dev/null check_rc $? else msg_warn "$BIN_PATH already exists!" fi - echo -n -e "Create path $BIN_PATH/lib: " - if [ ! -d "$BIN_PATH/lib" ]; then - mkdir -p "$BIN_PATH/lib" 2>/dev/null - check_rc $? - else - msg_warn "$BIN_PATH/lib already exists!" - fi - - echo -e -n "Create $BIN_PATH/bin: " + echo -n -e "Create path $BIN_PATH/bin: " if [ ! -d "$BIN_PATH/bin" ]; then - mkdir -p $BIN_PATH/bin 2>/dev/null + mkdir -p "$BIN_PATH/bin" 2>/dev/null check_rc $? else msg_warn "$BIN_PATH/bin already exists!" - fi + fi echo -e -n "Create $BIN_PATH/config: " if [ ! -d "$BIN_PATH/config" ]; then @@ -137,33 +95,48 @@ main(){ msg_warn "$CONF_PATH already exists!" fi -# copy config file +# create paths for certs repository + echo -e -n "Create $CERTS_PATH: " + if [ ! -d "$CERTS_PATH" ]; then + mkdir -p $CERTS_PATH 2>/dev/null + check_rc $? + else + msg_warn "$CERTS_PATH already exists!" + fi + + echo -e -n "Create $KEY_CA_PATH: " + if [ ! -d "$KEY_CA_PATH" ]; then + mkdir -p $KEY_CA_PATH 2>/dev/null + check_rc $? + else + msg_warn "$KEY_CA_PATH already exists!" + fi + + echo -e -n "Create $CRT_CA_PATH: " + if [ ! -d "$CRT_CA_PATH" ]; then + mkdir -p $CRT_CA_PATH 2>/dev/null + check_rc $? + else + msg_warn "$CRT_CA_PATH already exists!" + fi + +# copy config default file echo -e -n "Copy ${ORANGE}$ROOT_DIR/config/default.conf${NC} to $BIN_PATH/config: " cp "$ROOT_DIR/config/default.conf" "$BIN_PATH/config/." check_rc $? -# copy config file - echo -e -n "Copy ${ORANGE}$ROOT_DIR/config/default.conf${NC} to $BIN_PATH/config: " - cp "$ROOT_DIR/config/default.conf" "$BIN_PATH/config/." - check_rc $? +# copy config own-pki.conf file + if [[ "$COPY_CONF" == "true" ]]; then + echo -e -n "Copy ${ORANGE}$ROOT_DIR/config/own-pki.conf${NC} to $CONF_PATH: " + cp "$ROOT_DIR/config/own-pki.conf" "$CONF_PATH/." + check_rc $? + fi -# copy config file +# copy ca config file echo -e -n "Copy ${ORANGE}$ROOT_DIR/config/ca-config.tmpl${NC} to ${BIN_PATH}/config: " cp "$ROOT_DIR/config/ca-config.tmpl" "${BIN_PATH}/config/." check_rc $? -# create DB - echo -n -e "Create DB $DB_PATH: " - if [ -f "$DB_PATH" ]; then - msg_warn "$DB_PATH already exists!" - yes_no "Are you sure you want to recreate a database" - rm -rf "$DB_PATH" - init_db - check_rc $? - else - init_db - check_rc $? - fi # copy script file to opt msg_info "Copy librairie scripts files" @@ -185,18 +158,12 @@ main(){ fi done - msg_info "Create link" - files=( $ROOT_DIR/bin/* ) - for f in "${files[@]}"; do - # exclude install.sh - if [ "$f" != "$ROOT_DIR/bin/install.sh" ]; then - SCRIPT_FILE=$(basename "$f") - echo -e -n " create link ${ORANGE}$BIN_PATH/bin/$SCRIPT_FILE${NC} to /usr/local/bin/: " - ln -f -s $BIN_PATH/bin/$SCRIPT_FILE /usr/local/bin/ #>"$out_tmp" 2>"$err_tmp" - check_rc $? - - fi - done + echo "******************************************************" + echo " Installation completed !!" + echo -e " Adapt the file ${ORANGE}$CONF_PATH/own-pki.conf${NC} as you need" + echo "******************************************************" + + } main "$@" diff --git a/bin/random-cert.sh b/bin/random-cert.sh new file mode 100755 index 0000000..95b767d --- /dev/null +++ b/bin/random-cert.sh @@ -0,0 +1,161 @@ +#/bin/bash + +generate_cert() { + local CA_CRT="" + local CA_KEY="" + local COMMON_NAME="" + local DAYS="$DAYS" + local DNS=() + local IP_ADDRS=() + + # parsing arguments + while [[ $# -gt 0 ]]; do + case "$1" in + -c) CA_CRT=$2.crt; CA_KEY=$2.key ;shift 2 ;; + -n) COMMON_NAME="$2"; shift 2 ;; + -d) DNS_LINE="$COMMON_NAME,$2"; shift 2 ;; + -i) IP_ADDRS_LINE=("$2"); shift 2 ;; + -t) DAYS="$2"; shift 2 ;; + *) echo "Option inconnue: $1"; return 1 ;; + esac + done + IFS=',' read -r -a IP_ADDRS <<< "$IP_ADDRS_LINE" + IFS=',' read -r -a DNS <<< "$DNS_LINE" + if [ "${#DNS[@]}" -eq 0 ]; then + DNS+="$COMMON_NAME" + fi + + cat > "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" << EOF +[ req ] +default_bits = 2048 +distinguished_name = req_distinguished_name +req_extensions = req_ext +prompt = no + +[ req_distinguished_name ] +CN = $COMMON_NAME + +[ req_ext ] +subjectAltName = @alt_names + +[ alt_names ] +EOF + + # Add san dns" + idns=1 + for SAN_DNS in "${DNS[@]}"; do + echo "DNS.$idns = $SAN_DNS" >> "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" + ((idns++)) + done + + # add san ip + iip=1 + for SAN_IP in "${IP_ADDRS[@]}"; do + echo "IP.$iip = $SAN_IP" >> "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" + ((iip++)) + done + + # create certificate + echo -e "Generating the private key..." + openssl genrsa -out "${CERTS_PATH}/${COMMON_NAME}.key" 4096 + + echo -e "Generating csr file..." + openssl req -new -key "${CERTS_PATH}/${COMMON_NAME}.key" -out "${CERTS_PATH}/${COMMON_NAME}.csr" -config "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" + + echo -e "Signing the certificate with the CA..." + openssl x509 -req -in "${CERTS_PATH}/${COMMON_NAME}.csr" \ + -CA "$CRT_CA_PATH/$CA_CRT" -CAkey "$KEY_CA_PATH/$CA_KEY" -CAcreateserial \ + -out "${CERTS_PATH}/${COMMON_NAME}.crt" -days "$DAYS" \ + -extensions req_ext -extfile "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" \ + -passin pass:pa55w0rd \ + > /dev/null 2>&1 + rc=$? + echo -n "Result of certificate signing: " + check_rc $rc +} + +# Fonction pour générer un FQDN +gen_fqdn() { + local sub_len=$((RANDOM % 8 + 3)) + local name_len=$((RANDOM % 13 + 3)) + + local sub=$(tr -dc 'a-z0-9' /dev/null 2>&1 + rc=$? + echo -n -e "Result of signing the ${ORANGE}$COMMON_NAME${NC} certificate: " + check_rc $rc + echo -e "" + done + fi + shift 2 + ;; + -v|--version) + cat << EOF +$(basename "$0") $version Copyright (C) 2003 - $(date +%Y) Gilles Mouchet +EOF + exit + ;; + *|-h|--help) + usage + exit + ;; + esac + done +} +main "$@" \ No newline at end of file diff --git a/config/ca-config b/config/ca-config new file mode 100644 index 0000000..b1b6c52 --- /dev/null +++ b/config/ca-config @@ -0,0 +1,102 @@ +HOME = . +RANDFILE = $ENV::HOME/.rnd +oid_section = new_oids + +[ new_oids ] + +[ ca ] +default_ca = CA_default # The default ca section +[ CA_default ] +dir = . # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/dbca/index.txt # database index file. +new_certs_dir = $dir/newcerts # default place for new certs. +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial/serial # The current serial number +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file +x509_extensions = usr_cert # The extentions to add to the cert +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = md5 # which md to use. +preserve = no # keep passed DN ordering +policy = policy_match + +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert +string_mask = nombstr + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = CH +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Vaud + +localityName = Locality Name (eg, city) +localityName_default = Nyon + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = GMO Lab (gmolab) + +organizationalUnitName = Organizational Unit Name (eg, section) + +organizationalUnitName_default = ITCS (Information Technology and Communications Service) + +commonName = Common Name (eg, YOUR name) +commonName_default = +commonName_max = 64 + +emailAddress = Email Address +emailAddress_default = example@example.com +emailAddress_max = 40 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] +basicConstraints=CA:FALSE +nsComment = "OpenSSL Generated Certificate" +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +[ v3_req ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints = CA:true + +[ crl_ext ] +authorityKeyIdentifier=keyid:always,issuer:always \ No newline at end of file diff --git a/config/default.conf b/config/default.conf index 6e3b2c0..f96ea0f 100644 --- a/config/default.conf +++ b/config/default.conf @@ -1,16 +1,25 @@ -# Enables colorization (true) or disables it (false) -ENABLE_COLOR=true +# Path to config file +CONF_PATH=/etc/own-pki + +# Path to certificate files +CERTS_PATH=/var/lib/own-pki/certs # Path to the certificate authority's private key file -KEY_CA_PATH=/etc/pki/tls/private +KEY_CA_PATH=/var/lib/own-pki/ca/key # Path to the certificate authority's public key file -CRT_CA_PATH=/etc/pki/tls/certs +CRT_CA_PATH=/var/lib/own-pki/ca/crt + +# Path to pki scripts +BIN_PATH=/opt/own-pki + +# Enables colorization (true) or disables it (false) +ENABLE_COLOR=true # Default number of days for the certificate's validity # This can be overridden with the `-t or --days` option # when running the script. -DAYS=365 +DAYS=375 # Variables to use for create ca-config file # Country Name (2 letter code) @@ -44,9 +53,3 @@ DEBUG=false # 0 = Ask confirmation # 1 = does not ask confirmation ASSUME_YES=0 - -# Temp path for certificates files -CERTS_TMP_PATH=/tmp/ca - -# Databse -DB_PATH=/var/lib/own-pki/certificates.db \ No newline at end of file diff --git a/config/own-pki.conf b/config/own-pki.conf index b5fec24..f23a326 100644 --- a/config/own-pki.conf +++ b/config/own-pki.conf @@ -1,12 +1,6 @@ # Enables colorization (true) or disables it (false) #ENABLE_COLOR=true -# Path to the certificate authority's private key file -#KEY_CA_PATH=/etc/pki/tls/private - -# Path to the certificate authority's public key file -#CRT_CA_PATH=/etc/pki/tls/certs - # Default number of days for the certificate's validity # This can be overridden with the `-t or --days` option # when running the script. @@ -35,5 +29,25 @@ # Email address #EMAIL_ADDRESS=example@example.com -# Temp path for certificates files -#CERTS_TMP_PATH=/tmp/ca \ No newline at end of file +# Debug +# false = debug inactive +# true = debug active +#DEBUG=false + +# Automatically answers yes to the questions +# 0 = Ask confirmation +# 1 = does not ask confirmation +#ASSUME_YES=0 + +# If you change a path below, you must run 'sudo ./install.sh --reload-conf'. +# Path to certificate files +#CERTS_PATH=/var/lib/own-pki/certs + +# Path to the certificate authority's private key file +#KEY_CA_PATH=/var/lib/ca/key + +# Path to the certificate authority's public key file +#CRT_CA_PATH=/var/lib/ca/crt + +# Path to pki scripts +#BIN_PATH=/opt/own-pki diff --git a/lib/.gitkeep b/lib/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/lib/check-rc.sh b/lib/check-rc.sh-old similarity index 70% rename from lib/check-rc.sh rename to lib/check-rc.sh-old index 2349d90..f7056f4 100644 --- a/lib/check-rc.sh +++ b/lib/check-rc.sh-old @@ -1,6 +1,6 @@ # check if run from script [[ "${BASH_SOURCE[0]}" == "${0}" ]] && exit 1 - +#------------------------------------------------------------------------------ check_rc(){ if [ "$1" != "0" ]; then msg_error "Error (RC:$rc)" diff --git a/lib/core.sh b/lib/core.sh index e05b844..e3dfb32 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -1,13 +1,14 @@ # check if run from script [[ "${BASH_SOURCE[0]}" == "${0}" ]] && exit 1 +#------------------------------------------------------------------------------ +# read default param init_default(){ -# read default conf file DEFAULT_CONF="${ROOT_DIR}/config/default.conf" [[ -f "$DEFAULT_CONF" ]] && source "$DEFAULT_CONF" - } - +#------------------------------------------------------------------------------ +# read param from config file init_env() { # read config file CONFIG_FILE="/etc/own-pki/own-pki.conf" @@ -20,7 +21,16 @@ init_env() { out_tmp=$(mktemp) err_tmp=$(mktemp) } - +#------------------------------------------------------------------------------ +# read credential from /root/.cred file +init_cred(){ + CRED_FILE=/root/.cred + [[ -f "$CRED_FILE" ]] && source "$CRED_FILE"|| msg_error "File ${ORANGE}$CRED_FILE${RED} missing.${NC}" +} +#------------------------------------------------------------------------------ +# clean string +# input: string to clean +# output: string cleaned clean_string() { echo "$1" | \ # translate special chars to closest ASCII (e.g., 'é' -> 'e') @@ -34,7 +44,26 @@ clean_string() { # remove underscores at the beginning or end sed -E 's/^_|_$//g' } - +#------------------------------------------------------------------------------ +# check format fqdn +# input: fqdn to check +check_format_fqdn(){ + if [[ ! "$1" =~ ^([a-z0-9]+(-[a-z0-9]+)*\.){2,}[a-z]{2,}$ ]]; then + msg_error "\n$1 is not a fqdn valid.\n" + exit 1 + fi +} +#------------------------------------------------------------------------------ +# check format ip address +# input: ip address to check +check_format_ip(){ + if [[ ! "$1" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]; then + msg_error "\n$1 is not an address IP valid.\n" + exit 1 + fi +} +#------------------------------------------------------------------------------ +# check if the user has sudo privileges and ensure that the script runs with sudo. check_sudo(){ # check if user has sudo rigth if sudo ! -n true 2>/dev/null; then @@ -47,5 +76,50 @@ check_sudo(){ msg_error "\nThis script must be run as root or with sudo.\n" exit 1 fi - } +#------------------------------------------------------------------------------ +# check the return code +check_rc(){ + if [ "$1" != "0" ]; then + msg_error "Error (RC:$rc)" + exit 1 + else + msg_ok "OK" + fi +} +#----------------------------------------------------------- +# set colors +# RED Error +# ORANGE Attention or color for parameters when +# confirmation +# CYAN Ask to user or display a data +# GREEN OK +set_color(){ + if [[ "$ENABLE_COLOR" == "true" ]]; then + RED='\e[0;31m' + ORANGE='\e[0;33m' + CYAN='\e[0;36m' + GREEN='\e[0;32m' + NC='\e[0m' + else + RED='' + ORANGE='' + CYAN='' + GREEN='' + NC='' + fi +} +#----------------------------------------------------------- +# ask question yes or no +# input: prompt +yes_no(){ + if [ "$ASSUME_YES" == "0" ]; then + echo -n -e "${CYAN}$1 [y/N]? ${NC}" + unset answer + read answer + if [ "${answer}" != "y" ]; then + echo -e "${ORANGE}Canceled!${NC}" + exit 1 + fi + fi +} \ No newline at end of file diff --git a/lib/expired-date.sh b/lib/expired-date.sh new file mode 100644 index 0000000..0878e7b --- /dev/null +++ b/lib/expired-date.sh @@ -0,0 +1,55 @@ + +# check if run from script +[[ "${BASH_SOURCE[0]}" == "${0}" ]] && exit 1 + +#------------------------------------------------------------------------------ +# this funtcion return the expireDate array with +# data daysLeft|cn|exp +expired_date(){ + nbrDays=$1 + # set tmp file + tmpFile=$(mktemp) + # set date now in timestamp Unix + # timesatmp Unix = number of seconds elapsed + # since January 1, 1970 at 00:00:00 UTC (called epoch) + now=$(date -u +%s) + + # test expired cert + #today=$(date +%s) + #now=$((today + 7*24*60*60)) # today +7 days + + # read file list + certList=() + # set - if no .crt → files=() (empty) + shopt -s nullglob + certList=($CERTS_PATH/*.crt) + shopt -u nullglob + if [ "${#certList[@]}" -gt "0" ]; then + for crtFile in "${certList[@]}"; do + # set data from certfificate + cn=$(openssl x509 -noout -subject -in $crtFile | cut -d"=" -f3) + expiration=$(openssl x509 -noout -in $crtFile -enddate | cut -d"=" -f2) + # convert in timestamp Unix + exp=$(date -u -d "$expiration" +%s) + diffSec=$((exp - now)) + daysLeft=$(( (diffSec + 86399) / 86400 )) + # write in tmpfile valide cert + if [ "$exp" -ge "$now" ] && [ "$daysLeft" -le "$nbrDays" ]; then + echo "$daysLeft|$cn|$expiration" >> "$tmpFile" + fi + + # write in tmpfile expired cert + if [ "$exp" -lt "$now" ]; then + echo "$daysLeft|$cn|$expiration" >> "$tmpFile" + fi + done + fi + # put the content tmpfile in sorted array + expireDate=() + while IFS='|' read -r daysLeft cn exp; do + expireDate+=("$daysLeft|$cn|$exp") + done < <(sort -n "$tmpFile") + + # delete tmpfile + rm -rf tmpFile +} \ No newline at end of file diff --git a/lib/set-color.sh b/lib/set-color.sh-old similarity index 88% rename from lib/set-color.sh rename to lib/set-color.sh-old index 89eec51..74b758d 100644 --- a/lib/set-color.sh +++ b/lib/set-color.sh-old @@ -5,8 +5,8 @@ # set colors # RED Error # ORANGE Attention or color for parameters when -# confirmation -# CYAN Ask to useer +# confirmation +# CYAN Ask to user or display a data # GREEN OK set_color(){ if [[ "$ENABLE_COLOR" == "true" ]]; then diff --git a/lib/stdlib.sh b/lib/stdlib.sh index 350e5e5..a2d9b78 100644 --- a/lib/stdlib.sh +++ b/lib/stdlib.sh @@ -5,7 +5,8 @@ ROOT_DIR="$(dirname "$SCRIPT_DIR")" #source "$ROOT_DIR/lib/log.sh" #source "$ROOT_DIR/lib/error.sh" source "$ROOT_DIR/lib/core.sh" -source "$ROOT_DIR/lib/set-color.sh" +#source "$ROOT_DIR/lib/set-color.sh" source "$ROOT_DIR/lib/message.sh" -source "$ROOT_DIR/lib/check-rc.sh" -source "$ROOT_DIR/lib/yes-no.sh" \ No newline at end of file +#source "$ROOT_DIR/lib/check-rc.sh" +#source "$ROOT_DIR/lib/yes-no.sh" +source "$ROOT_DIR/lib/expired-date.sh" \ No newline at end of file diff --git a/lib/yes-no.sh b/lib/yes-no.sh-old similarity index 100% rename from lib/yes-no.sh rename to lib/yes-no.sh-old