This commit is contained in:
Gilles Mouchet 2026-04-26 20:44:39 +02:00
parent 8ad708c93e
commit 7c4cacc6bb
17 changed files with 1237 additions and 366 deletions

View File

@ -32,13 +32,13 @@ usage() {
Usage: ./$(basename "$0") -n <commonName> Usage: ./$(basename "$0") -n <commonName>
Template script Template script
Options: Options:
-n, --common-name <cn> - CA common name [mandatory] -n, --cn <cn> - CA common name [mandatory]
-h, --help - show this help -h, --help - show this help
-v, --version - show script version -v, --version - show script version
Examples: Examples:
Show this help Create CA called "GMOLab CA"
./$(basename "$0") -n "GMOLab CA" ./$(basename "$0") -n "GMOLab CA"
EOF EOF
} }
@ -90,7 +90,7 @@ $(basename "$0") $version Copyright (C) 2003 - $(date +%Y) Gilles Mouchet
EOF EOF
exit exit
;; ;;
*|help|-h|--help) *|-h|--help)
usage usage
exit exit
;; ;;
@ -120,9 +120,11 @@ Email address: ${ORANGE}%s${NC}
${RED}IMPORTANT${NC} ${RED}IMPORTANT${NC}
You will be asked for a password. Choose a ${RED}STRONG PASSWORD${NC} You will be asked for a password. Choose a ${RED}STRONG PASSWORD${NC}
and KEEP IT SECURE. and KEEP IT SECURE.
You will be asked for it when creating certificates. 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}" \ " "${KEY_CA_PATH}/${CA_NAME}" "${CRT_CA_PATH}/${CA_NAME}" \
"$COUNTRY_NAME" "$STATE_OR_PROVINCE_NAME" "$LOCALITY_NAME" \ "$COUNTRY_NAME" "$STATE_OR_PROVINCE_NAME" "$LOCALITY_NAME" \
"$ORGANIZATION_NAME" "$ORGANIZATIONAL_UNIT_NAME" "$COMMON_NAME" "$EMAIL_ADDRESS" "$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 # check if CA files exist
if [ -f "$KEY_CA_PATH/$CA_NAME.key" ]; then 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" msg_warn "\n$KEY_CA_PATH/$CA_NAME.key already exists!\n"
yes_no "Are you sure you want to delete it" yes_no "Are you sure you want to delete it"
fi fi

View File

@ -37,7 +37,7 @@ Usage: $0 -c <ca_cert> -k <ca_key> -n <common_name> [-d <dns1,dns2>] [-i <ip1,ip
Template script Template script
Options: Options:
-c, --ca-name <ca_name> - ca name (./info-cert.sh -c get list of CA name) -c, --ca-name <ca_name> - ca name (./info-cert.sh -c get list of CA name)
-n, --commonName <cn> - common name (server.domain.ext) -n, --commonName <cn> - common name fqdn format (server.domain.ext)
-d, --dns <dns1,dns2,dnsx> - subject alternative name (multiple SAN separated by commas) -d, --dns <dns1,dns2,dnsx> - subject alternative name (multiple SAN separated by commas)
-i, --ip <ip1,ipx> - ip address to add to the certificate (multiple IPs separated by commas) -i, --ip <ip1,ipx> - ip address to add to the certificate (multiple IPs separated by commas)
-t, --days <days> - validity period of the certificate in days (defaults $days days) -t, --days <days> - validity period of the certificate in days (defaults $days days)
@ -46,14 +46,12 @@ Options:
-v, --version - show script version -v, --version - show script version
Examples: Examples:
Generate a certificate for myweb.gmolab.net Generate a certificate for myweb.gmolab.net
./$(basename "$0") -c gmolab_ca -n myweb.gmolab.net ./$(basename "$0") -c gmolab_ca -n myweb.gmolab.net
Generate a certifciate for myweb.gmolab.net with dns alias and ip 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 ./$(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 EOF
} }
@ -88,163 +86,151 @@ fi
set_color set_color
# parse cli parameters # parse cli parameters
while [[ "$#" -gt 0 ]]; do while [[ "$#" -gt 0 ]]; do
case "$1" in case "$1" in
-c|--ca-name) -c|--ca-name)
if [[ -z "$2" || "$2" == -* ]]; then if [[ -z "$2" || "$2" == -* ]]; then
msg_error "\nError: Argument missing for option -c or --ca-name.\n" 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"
usage usage
exit 1 exit 1
else 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 COMMON_NAME=$2
# record for db if no option -d or --dns exist. # record for db if no option -d or --dns exist.
# some browser needed the commName in Subject Alternative Name # 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 DNS_LINE=$2 # record for db if no option -d or --dns exist. Some browser needed the commName in Subject Alternative Name
fi fi
fi shift 2
shift 2 ;;
;; -d|--dns)
-d|--dns) if [[ -z "$2" || "$2" == -* ]]; then
if [[ -z "$2" || "$2" == -* ]]; then msg_error "\nError: Argument missing for option -d or --dns.\n"
msg_error "\nError: Argument missing for option -d or --dns.\n" usage
usage exit 1
exit 1 else
else # add commonName and parameters -d --dns value in dnsLine variable.
# add commonName and parameters -d --dns value in dnsLine variable. # some browser needed the commName in Subject Alternative Name
# some browser needed the commName in Subject Alternative Name DNS_LINE="$COMMON_NAME,$2"
DNS_LINE="$COMMON_NAME,$2"
# put dnsLine value in dns array
# put dnsLine value in dns array IFS=',' read -r -a DNS <<< "$DNS_LINE"
IFS=',' read -r -a DNS <<< "$DNS_LINE"
# check dns format
# check dns format for SAN_DNS in "${DNS[@]}"; do
for SAN_DNS in "${DNS[@]}"; do check_format_fqdn $SAN_DNS
if [[ ! $SAN_DNS =~ ^([a-z0-9]+(-[a-z0-9]+)*\.){2,}[a-z]{2,}$ ]]; then done
msg_error "\n$SAN_DNS is not a commonName valid.\n" fi
exit 1 shift 2
fi ;;
done -i|--ip)
fi if [[ -z "$2" || "$2" == -* ]]; then
shift 2 msg_error "\nError: Argument missing for option -i or --ip.\n"
;; usage
-i|--ip) exit 1
if [[ -z "$2" || "$2" == -* ]]; then else
msg_error "\nError: Argument missing for option -i or --ip.\n" # add parameters -i --ip values in IP_LINE variable.
usage IP_LINE=$2
exit 1 # put ipLine value in ipAddrs array
else IFS=',' read -r -a IP_ADDRS <<< "$2"
# add parameters -i --ip values in IP_LINE variable.
IP_LINE=$2 # check ip format
# put ipLine value in ipAddrs array for SAN_IP in "${IP_ADDRS[@]}"; do
IFS=',' read -r -a IP_ADDRS <<< "$2" check_format_ip $SAN_IP
done
# check ip format fi
for SAN_IP in "${IP_ADDRS[@]}"; do shift 2
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" -t|--days)
exit 1 if [[ -z "$2" || "$2" == -* ]]; then
fi msg_err "\nError: Argument missing for option -t or --days.\n"
done usage
fi exit 1
shift 2 else
;; DAYS=$2
-t|--days) fi
if [[ -z "$2" || "$2" == -* ]]; then shift 2
msg_err "\nError: Argument missing for option -t or --days.\n" ;;
usage -y|--assumeyes)
exit 1 ASSUME_YES="1"
else shift
DAYS=$2 ;;
fi -v|--version)
shift 2 cat << EOF
;;
-y|--assumeyes)
ASSUME_YES="1"
shift
;;
-v|--version)
cat << EOF
$(basename "$0") $version Copyright (C) 2003 - $(date +%Y) Gilles Mouchet $(basename "$0") $version Copyright (C) 2003 - $(date +%Y) Gilles Mouchet
EOF EOF
exit exit
;; ;;
-h|--help) *|-h|--help)
usage usage
exit exit
;; ;;
esac esac
done done
# if array dns is empty we add commonName # check if file doesn't exists
if [ "${#DNS[@]}" -eq 0 ]; then if [ -f "$CERTS_PATH/$COMMON_NAME.key" ]; then
DNS+="$COMMON_NAME" echo -e "The ${ORANGE}$CERTS_PATH/$COMMON_NAME.key${NC} file exists!"
fi yes_no "Are you sure you want to continue"
fi
# check if mandatory variables exists
if [[ -z "$CA_CRT" || -z "$CA_KEY" || -z "$COMMON_NAME" ]]; then # if array dns is empty we add commonName
usage if [ "${#DNS[@]}" -eq 0 ]; then
exit 1 DNS+="$COMMON_NAME"
fi fi
# check if ca key and ca crt file exist # check if mandatory variables exists
if [[ ! -f "$CRT_CA_PATH/$CA_CRT" || ! -f "$KEY_CA_PATH/$CA_KEY" ]]; then if [[ -z "$CA_CRT" || -z "$CA_KEY" || -z "$COMMON_NAME" ]]; then
msg_error "One or both of the following files are missing:" usage
msg_warn " - $CRT_CA_PATH/$CA_CRT" exit 1
msg_warn " - $KEY_CA_PATH/$CA_KEY" fi
exit 1
fi # check if ca key and ca crt file exist
# summary if [[ ! -f "$CRT_CA_PATH/$CA_CRT" || ! -f "$KEY_CA_PATH/$CA_KEY" ]]; then
printf " 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 ${CYAN}Summary
---------------------------------------------------------------------${NC} ---------------------------------------------------------------------${NC}
Certifcate authority: ${GREEN}%s${NC} Certifcate authority: ${GREEN}%s${NC}
Common name: ${GREEN}%s${NC} Common name: ${GREEN}%s${NC}
" "$CRT_CA_PATH/$CA_CRT" "$COMMON_NAME" " "$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:" echo -e "\nPrepare the openSSL configuration file"
for SAN_DNS in "${DNS[@]}"; do cat > "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" << EOF
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
[ req ] [ req ]
default_bits = 2048 default_bits = 2048
distinguished_name = req_distinguished_name distinguished_name = req_distinguished_name
@ -260,83 +246,86 @@ subjectAltName = @alt_names
[ alt_names ] [ alt_names ]
EOF EOF
echo -e " Add SAN" echo -e " Add SAN"
# add dns # add dns
i=1 i=1
#echo "DNS.$i = ${COMMON_NAME}" >> "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" for SAN_DNS in "${DNS[@]}"; do
#((i++)) echo "DNS.$i = $SAN_DNS" >> "$CERTS_PATH/${COMMON_NAME}_openssl.cnf"
for SAN_DNS in "${DNS[@]}"; do ((i++))
echo "DNS.$i = $AN_DNS" >> "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" done
((i++))
done echo -e " Add IP"
# add ip
echo -e " Add IP" i=1
# add ip for SAN_IP in "${IP_ADDRS[@]}"; do
i=1 echo "IP.$i = $SAN_IP" >> "$CERTS_PATH/${COMMON_NAME}_openssl.cnf"
for SAN_IP in "${IP_ADDRS[@]}"; do ((i++))
echo "IP.$i = $SAN_IP" >> "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" done
((i++))
done # create certificate
echo -e "Generating the private key..."
# create certificate openssl genrsa -out "${CERTS_PATH}/${COMMON_NAME}.key" 4096
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_PATH}/${COMMON_NAME}.key" -out "${CERTS_PATH}/${COMMON_NAME}.csr" -config "$CERTS_PATH/${COMMON_NAME}_openssl.cnf"
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_PATH}/${COMMON_NAME}.csr" \
echo -e "Signing the certificate with the CA..." -CA "$CRT_CA_PATH/$CA_CRT" -CAkey "$KEY_CA_PATH/$CA_KEY" -CAcreateserial \
openssl x509 -req -in "${CERTS_TMP_PATH}/${COMMON_NAME}.csr" \ -out "${CERTS_PATH}/${COMMON_NAME}.crt" -days "$DAYS" \
-CA "$CRT_CA_PATH/$CA_CRT" -CAkey "$KEY_CA_PATH/$CA_KEY" -CAcreateserial \ -extensions req_ext -extfile "$CERTS_PATH/${COMMON_NAME}_openssl.cnf" \
-out "${CERTS_TMP_PATH}/${COMMON_NAME}.crt" -days "$DAYS" \ #-passin pass:$KEY_CA_PASS \
-extensions req_ext -extfile "$CERTS_TMP_PATH/${COMMON_NAME}_openssl.cnf" \ > /dev/null 2>&1
> /dev/null 2>&1 #-passin pass:pa55w0rd > /dev/null 2>&1 rc=$?
echo -n "Result of certificate signing: " echo -n "Result of certificate signing: "
check_rc $? check_rc $rc
#echo -e "\nVerify certifcate" #echo -e "\nVerify certifcate"
#echo -e "\nValidity" #echo -e "\nValidity"
#openssl x509 -in $CERTS_TMP_PATH/${COMMON_NAME}.crt -noout -dates #openssl x509 -in $CERTS_PATH/${COMMON_NAME}.crt -noout -dates
#echo -e "\nSubject Alternative Name" #echo -e "\nSubject Alternative Name"
#openssl x509 -in $CERTS_TMP_PATH/${COMMON_NAME}.crt -noout -ext subjectAltName #openssl x509 -in $CERTS_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: " 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_TMP_PATH/$COMMON_NAME.crt > /dev/null 2>&1 openssl verify -CAfile $CRT_CA_PATH/$CA_CRT $CERTS_PATH/$COMMON_NAME.crt > /dev/null 2>&1
check_rc $? check_rc $?
# get validity date # get validity date
NOT_BEFORE=$(openssl x509 -noout -in $CERTS_TMP_PATH/${COMMON_NAME}.crt -startdate | 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_TMP_PATH/${COMMON_NAME}.crt -enddate | 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 # check if commonName already exist on db
echo -e -n "\nCheck if ${GREEN}${COMMON_NAME}${NC} exist in 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}');") #recordExist=$(sqlite3 $DB_PATH "SELECT EXISTS(SELECT 1 FROM certs WHERE common_name='${COMMON_NAME}');")
check_rc $? #check_rc $?
if [ "$recordExist" == "1" ]; then #if [ "$recordExist" == "1" ]; then
echo -e -n "Update ${ORANGE}${COMMON_NAME}${NC} in DB: " # echo -e -n "Update ${ORANGE}${COMMON_NAME}${NC} in DB: "
sqlite3 $DB_PATH <<EOF ## cert_crt_64=$(base64 -w0 ${CERTS_TMP_PATH}/${COMMON_NAME}.crt)
UPDATE certs SET san_dns = '$DNS_LINE', ## echo $cert_crt_64
san_ip = '$IP_LINE',
cert_key = readfile('${CERTS_TMP_PATH}/${COMMON_NAME}.key'), # sqlite3 $DB_PATH <<EOF
cert_csr = readfile('${CERTS_TMP_PATH}/${COMMON_NAME}.csr'), #UPDATE certs SET san_dns = '$DNS_LINE',
cert_crt = readfile('${CERTS_TMP_PATH}/${COMMON_NAME}.crt'), # san_ip = '$IP_LINE',
not_valid_before = '$NOT_BEFORE', # cert_key = '$(base64 -w0 ${CERTS_TMP_PATH}/${COMMON_NAME}.key)',
not_valid_after = '$NOT_AFTER' # cert_csr = '$(base64 -w0 ${CERTS_TMP_PATH}/${COMMON_NAME}.csr)',
WHERE common_name = '${COMMON_NAME}'; # cert_crt = '$(base64 -w0 ${CERTS_TMP_PATH}/${COMMON_NAME}.crt)',
EOF # not_valid_before = '$NOT_BEFORE',
check_rc $? # not_valid_after = '$NOT_AFTER'
else #WHERE common_name = '${COMMON_NAME}';
echo -e -n "Add ${ORANGE}${COMMON_NAME}${NC} in DB: " #EOF
sqlite3 $DB_PATH <<EOF ## check_rc $?
INSERT INTO certs (common_name,san_dns,san_ip,cert_key,cert_csr,cert_crt,not_valid_before,not_valid_after) #else
VALUES ('${COMMON_NAME}', '$DNS_LINE','$IP_LINE', # echo -e -n "Add ${ORANGE}${COMMON_NAME}${NC} in DB: "
readfile('${CERTS_TMP_PATH}/${COMMON_NAME}.key'), # sqlite3 $DB_PATH <<EOF
readfile('${CERTS_TMP_PATH}/${COMMON_NAME}.csr'), #INSERT INTO certs (common_name,san_dns,san_ip,cert_key,cert_csr,cert_crt,not_valid_before,not_valid_after)
readfile('${CERTS_TMP_PATH}/${COMMON_NAME}.crt'), #VALUES ('${COMMON_NAME}', '$DNS_LINE','$IP_LINE',
'$NOT_BEFORE', # '$(base64 -w0 ${CERTS_TMP_PATH}/${COMMON_NAME}.key)',
'$NOT_AFTER') # '$(base64 -w0 ${CERTS_TMP_PATH}/${COMMON_NAME}.csr)',
EOF # '$(base64 -w0 ${CERTS_TMP_PATH}/${COMMON_NAME}.crt)',
check_rc $? # '$NOT_BEFORE',
fi # '$NOT_AFTER')
#EOF
# check_rc $?
#fi
} }
main "$@" main "$@"

258
bin/info-cert.sh Executable file
View File

@ -0,0 +1,258 @@
#!/bin/bash
#############################################################
# Script name: template.sh
# Author: Gilles Mouchet (gilles.mouchet@gmail.com
# Version: v1beta 2026-04-05
# Description: Script template linux
# License: CC BY-NC 4.0 (https://creativecommons.org/licenses/by-nc/4.0/)
#
# This script is provided "as is", WITHOUT ANY WARRANTY OF ANY KIND.
# Commercial use is strictly prohibited without prior authorization.
#
# Changelog
# [1.0.0] - 2026-04-05
# Added:
# - show certificate info
# - show ca list
# - show expiration date
# Project initialization
# - initialization by gilles.mouchet@gmail.com
#
############################################################
#
version=1.0.0
############################################################
# FUNCTIONS
############################################################
#-----------------------------------------------------------
# Display usage
usage() {
cat << EOF
Usage: ./$(basename "$0") options
Template script
Options:
-a, --all
Show all cert information
-c, --ca
List all CA name
-d, --expire-day <days>
List the certificates expiring in the next <days> days
-i, --info <ca_name_pattern>
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 "$@"

View File

@ -15,111 +15,69 @@
# [1.0.0] - 2026-04-12 # [1.0.0] - 2026-04-12
# - Added # - Added
# - create environment for cert # - create environment for cert
# - create DB
# - Project initialization # - Project initialization
# - initialization by gilles.mouchet@gmail.com # - initialization by gilles.mouchet@gmail.com
# #
############################################################ ############################################################
# #
set -Eeuo pipefail
VERSION=1.0.0 VERSION=1.0.0
############################################################
# FUNCTIONS
############################################################
#-----------------------------------------------------------
# init db
init_db(){
mkdir -p "$(dirname "$DB_PATH")"
sqlite3 $DB_PATH <<EOF
CREATE TABLE IF NOT EXISTS certs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
common_name TEXT UNIQUE,
san_dns TEXT,
san_ip TEXT,
cert_key TEXT,
cert_csr TEXT,
cert_crt TEXT,
not_valid_before TEXT,
not_valid_after TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER IF NOT EXISTS update_certs_updated_at
AFTER UPDATE ON certs
FOR EACH ROW
BEGIN
UPDATE certs
SET updated_at = CURRENT_TIMESTAMP
WHERE id = OLD.id;
END;
EOF
}
############################################################ ############################################################
# Main # Main
############################################################ ############################################################
#main (){
# path resolution # path resolution
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" #SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(dirname "$SCRIPT_DIR")" #ROOT_DIR="$(dirname "$SCRIPT_DIR")"
CONF_PATH="/etc/own-pki" #CONF_PATH="/etc/own-pki"
ENABLE_COLOR=true #ENABLE_COLOR=true
BIN_PATH="/opt/own-pki" #BIN_PATH="/opt/own-pki"
DB_PATH="/var/lib/own-pki/certificates.db" #ASSUME_YES=0
ASSUME_YES=0
# read stdlib.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"
set_color
main(){ main(){
# check if user has sudo rigth SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if sudo ! -n true 2>/dev/null; then ROOT_DIR="$(dirname "$SCRIPT_DIR")"
msg_error "Access denied: user $USER does not have sudo privileges or a password is required.." COPY_CONF=true
exit 1
fi
# check if the effective user ID is 0 (root) # read library
if [[ $EUID -ne 0 ]]; then source "$ROOT_DIR/lib/stdlib.sh"
msg_error "\nThis script must be run as root or with sudo.\n"
exit 1 # init config
fi init_default
# set color
set_color
# check if script is run with sudo
check_sudo
# install sqlite # read cli parameters
echo -n -e "Install ${ORANGE}sqlite${NC}. Please wait...: " while [[ "$#" -gt 0 ]]; do
dnf install sqlite -y > /dev/null 2>&1 case "$1" in
check_rc $? --reload-conf)
init_env
# create paths COPY_CONF=false
echo -n -e "Create path $BIN_PATH: " shift
if [ ! -d "$BIN_PATH" ]; then ;;
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 mkdir -p "$BIN_PATH" 2>/dev/null
check_rc $? check_rc $?
else else
msg_warn "$BIN_PATH already exists!" msg_warn "$BIN_PATH already exists!"
fi fi
echo -n -e "Create path $BIN_PATH/lib: " echo -n -e "Create path $BIN_PATH/bin: "
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: "
if [ ! -d "$BIN_PATH/bin" ]; then if [ ! -d "$BIN_PATH/bin" ]; then
mkdir -p $BIN_PATH/bin 2>/dev/null mkdir -p "$BIN_PATH/bin" 2>/dev/null
check_rc $? check_rc $?
else else
msg_warn "$BIN_PATH/bin already exists!" msg_warn "$BIN_PATH/bin already exists!"
fi fi
echo -e -n "Create $BIN_PATH/config: " echo -e -n "Create $BIN_PATH/config: "
if [ ! -d "$BIN_PATH/config" ]; then if [ ! -d "$BIN_PATH/config" ]; then
@ -137,33 +95,48 @@ main(){
msg_warn "$CONF_PATH already exists!" msg_warn "$CONF_PATH already exists!"
fi 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: " echo -e -n "Copy ${ORANGE}$ROOT_DIR/config/default.conf${NC} to $BIN_PATH/config: "
cp "$ROOT_DIR/config/default.conf" "$BIN_PATH/config/." cp "$ROOT_DIR/config/default.conf" "$BIN_PATH/config/."
check_rc $? check_rc $?
# copy config file # copy config own-pki.conf file
echo -e -n "Copy ${ORANGE}$ROOT_DIR/config/default.conf${NC} to $BIN_PATH/config: " if [[ "$COPY_CONF" == "true" ]]; then
cp "$ROOT_DIR/config/default.conf" "$BIN_PATH/config/." echo -e -n "Copy ${ORANGE}$ROOT_DIR/config/own-pki.conf${NC} to $CONF_PATH: "
check_rc $? 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: " 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/." cp "$ROOT_DIR/config/ca-config.tmpl" "${BIN_PATH}/config/."
check_rc $? 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 # copy script file to opt
msg_info "Copy librairie scripts files" msg_info "Copy librairie scripts files"
@ -185,18 +158,12 @@ main(){
fi fi
done done
msg_info "Create link" echo "******************************************************"
files=( $ROOT_DIR/bin/* ) echo " Installation completed !!"
for f in "${files[@]}"; do echo -e " Adapt the file ${ORANGE}$CONF_PATH/own-pki.conf${NC} as you need"
# exclude install.sh echo "******************************************************"
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
} }
main "$@" main "$@"

161
bin/random-cert.sh Executable file
View File

@ -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/urandom | fold -w "$sub_len" | head -n 1)
local name=$(tr -dc 'a-z0-9' </dev/urandom | fold -w "$name_len" | head -n 1)
local tld=("com" "net" "org" "io" "ch" "fr")
echo "${sub}.${name}.${tld[$((RANDOM % ${#tld[@]}))]}"
}
# Fonction IP
gen_ip() {
echo "$((RANDOM % 256)).$((RANDOM % 256)).$((RANDOM % 256)).$((RANDOM % 256))"
}
# Liste (fqdn ou ip)
gen_list() {
local type=$1
local count=$((RANDOM % 3 + 3))
local list=""
for ((i=0; i<count; i++)); do
local item
[[ "$type" == "fqdn" ]] && item=$(gen_fqdn) || item=$(gen_ip)
list+="$item"
[[ $i -lt $((count-1)) ]] && list+=","
done
echo "$list"
}
############################################################
# 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
echo "Début de la génération..."
for ((i=1; i<=10; i++)); do
args=()
fqdn=$(gen_fqdn)
# -d (50%)
if (( RANDOM % 2 )); then
args+=("-d" "$(gen_list fqdn)")
fi
# -i (50%)
if (( RANDOM % 2 )); then
args+=("-i" "$(gen_list ip)")
fi
# -t (50%)
if (( RANDOM % 2 )); then
args+=("-t" "$((RANDOM % $DAYS + 1))")
fi
echo "[$i/5] generate_cert -c gmolab_ca -n $fqdn ${args[*]}"
# Appel direct
generate_cert -c "gmolab_ca" -n "$fqdn" "${args[@]}"
# generate_cert -c gmolab_ca -n vwiy3rv1ui.6zghdqm1p8cj.io -d u0ba3i5rt.asfsdvrmf8iiltd.org,0sit366.w47txhyg.io,4ulkpy6.v39762sriaiy.com,zvw3o0ovee.gqv50o6ge6.io,a57v0x.rs8.net -i 161.21.147.75,81.67.128.79,81.54.192.190,95.116.177.195,13.111.172.161
done
echo "Génération terminée avec succès."
}
main "$@"

110
bin/remove-cert.sh Executable file
View File

@ -0,0 +1,110 @@
#!/bin/bash
#############################################################
# Script name: remove-cert.sh
# Author: Gilles Mouchet (gilles.mouchet@gmail.com
# Version: 1.0.0
# Description: Removes certificate from the database
# License: GNU GPL v3
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Changelog
# [1.0.0] - 2026-04-05
# Added:
# - new features
# Project initialization:
# - initialization by gilles.mouchet@gmail.com
#
############################################################
version=1.0.0
############################################################
# FUNCTIONS
############################################################
#-----------------------------------------------------------
# Display usage
usage() {
cat << EOF
Usage: ./$(basename "$0") options
Template script
Options:
-n, --cn
Delete the certificates from DB
To find the commonName, use the script ./info-cert.sh -h
-h, --help
Show this help
-v, --version
Show script version
Examples:
Show this help
./$(basename "$0") -h
Delete
EOF
}
############################################################
# 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
# read cli parameters
while [[ "$#" -gt 0 ]]; do
case "$1" in
-n|--cn)
if [[ -z "$2" || "$2" == -* ]]; then
echo -e "\n${RED}Error: Argument missing for option -n or --cn. See ./$(basename "$0") --help${NC}\n"
exit 1
else
# check if file exit
if [ ! -f "$CERTS_PATH/$2.crt" ] || [ ! -f "$CERTS_PATH/$2.key" ]; then
msg_error "$2.crt does not exist !"
else
echo -e "${ORANGE}$2${NC} will be deleted"
yes_no "Are you sure"
echo -e -n "$2 deleted: "
# * must be outside "..."
rm -f "$CERTS_PATH/${2}"*
check_rc $?
fi
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 "$@"

136
bin/renew-cert.sh Executable file
View File

@ -0,0 +1,136 @@
#!/bin/bash
#############################################################
# Script name: renew-cert.sh
# Author: Gilles Mouchet (gilles.mouchet@gmail.com
# Version: 1.0.0
# Description: Renews certificates that are about to expire
# License: GNU GPL v3
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Changelog
# [1.0.0] - 2026-04-05
# Added:
# - resign cert
# Project initialization:
# - initialization by gilles.mouchet@gmail.com
#
############################################################
version=1.0.0
############################################################
# FUNCTIONS
############################################################
#-----------------------------------------------------------
# Display usage
usage() {
cat << EOF
Usage: ./$(basename "$0") options
Template script
Options:
-n, --cn
Delete the certificates from DB
To find the commonName, use the script ./info-cert.sh -h
-h, --help
Show this help
-v, --version
Show script version
Examples:
Show this help
./$(basename "$0") -h
Delete
EOF
}
############################################################
# 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
init_cred
# 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
# read 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
;;
-d|--expire-date)
if [[ -z "$2" || "$2" == -* ]]; then
echo -e "\n${RED}Error: Argument missing for option -d or --expire-date. See ./$(basename "$0") --help${NC}\n"
exit 1
elif [[ "$2" =~ ^[0-9]+$ ]] && [ "$2" -ge 1 ] && [ "$2" -le "$DAYS" ]; then
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
expired_date $2
for certData in "${expireDate[@]}"; do
COMMON_NAME=$(echo $certData | cut -d"|" -f2 )
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 -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 "$@"

102
config/ca-config Normal file
View File

@ -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

View File

@ -1,16 +1,25 @@
# Enables colorization (true) or disables it (false) # Path to config file
ENABLE_COLOR=true 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 # 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 # 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 # Default number of days for the certificate's validity
# This can be overridden with the `-t or --days` option # This can be overridden with the `-t or --days` option
# when running the script. # when running the script.
DAYS=365 DAYS=375
# Variables to use for create ca-config file # Variables to use for create ca-config file
# Country Name (2 letter code) # Country Name (2 letter code)
@ -44,9 +53,3 @@ DEBUG=false
# 0 = Ask confirmation # 0 = Ask confirmation
# 1 = does not ask confirmation # 1 = does not ask confirmation
ASSUME_YES=0 ASSUME_YES=0
# Temp path for certificates files
CERTS_TMP_PATH=/tmp/ca
# Databse
DB_PATH=/var/lib/own-pki/certificates.db

View File

@ -1,12 +1,6 @@
# Enables colorization (true) or disables it (false) # Enables colorization (true) or disables it (false)
#ENABLE_COLOR=true #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 # Default number of days for the certificate's validity
# This can be overridden with the `-t or --days` option # This can be overridden with the `-t or --days` option
# when running the script. # when running the script.
@ -35,5 +29,25 @@
# Email address # Email address
#EMAIL_ADDRESS=example@example.com #EMAIL_ADDRESS=example@example.com
# Temp path for certificates files # Debug
#CERTS_TMP_PATH=/tmp/ca # 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

View File

View File

@ -1,6 +1,6 @@
# check if run from script # check if run from script
[[ "${BASH_SOURCE[0]}" == "${0}" ]] && exit 1 [[ "${BASH_SOURCE[0]}" == "${0}" ]] && exit 1
#------------------------------------------------------------------------------
check_rc(){ check_rc(){
if [ "$1" != "0" ]; then if [ "$1" != "0" ]; then
msg_error "Error (RC:$rc)" msg_error "Error (RC:$rc)"

View File

@ -1,13 +1,14 @@
# check if run from script # check if run from script
[[ "${BASH_SOURCE[0]}" == "${0}" ]] && exit 1 [[ "${BASH_SOURCE[0]}" == "${0}" ]] && exit 1
#------------------------------------------------------------------------------
# read default param
init_default(){ init_default(){
# read default conf file
DEFAULT_CONF="${ROOT_DIR}/config/default.conf" DEFAULT_CONF="${ROOT_DIR}/config/default.conf"
[[ -f "$DEFAULT_CONF" ]] && source "$DEFAULT_CONF" [[ -f "$DEFAULT_CONF" ]] && source "$DEFAULT_CONF"
} }
#------------------------------------------------------------------------------
# read param from config file
init_env() { init_env() {
# read config file # read config file
CONFIG_FILE="/etc/own-pki/own-pki.conf" CONFIG_FILE="/etc/own-pki/own-pki.conf"
@ -20,7 +21,16 @@ init_env() {
out_tmp=$(mktemp) out_tmp=$(mktemp)
err_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() { clean_string() {
echo "$1" | \ echo "$1" | \
# translate special chars to closest ASCII (e.g., 'é' -> 'e') # translate special chars to closest ASCII (e.g., 'é' -> 'e')
@ -34,7 +44,26 @@ clean_string() {
# remove underscores at the beginning or end # remove underscores at the beginning or end
sed -E 's/^_|_$//g' 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_sudo(){
# check if user has sudo rigth # check if user has sudo rigth
if sudo ! -n true 2>/dev/null; then 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" msg_error "\nThis script must be run as root or with sudo.\n"
exit 1 exit 1
fi 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
}

55
lib/expired-date.sh Normal file
View File

@ -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
}

View File

@ -5,8 +5,8 @@
# set colors # set colors
# RED Error # RED Error
# ORANGE Attention or color for parameters when # ORANGE Attention or color for parameters when
# confirmation # confirmation
# CYAN Ask to useer # CYAN Ask to user or display a data
# GREEN OK # GREEN OK
set_color(){ set_color(){
if [[ "$ENABLE_COLOR" == "true" ]]; then if [[ "$ENABLE_COLOR" == "true" ]]; then

View File

@ -5,7 +5,8 @@ ROOT_DIR="$(dirname "$SCRIPT_DIR")"
#source "$ROOT_DIR/lib/log.sh" #source "$ROOT_DIR/lib/log.sh"
#source "$ROOT_DIR/lib/error.sh" #source "$ROOT_DIR/lib/error.sh"
source "$ROOT_DIR/lib/core.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/message.sh"
source "$ROOT_DIR/lib/check-rc.sh" #source "$ROOT_DIR/lib/check-rc.sh"
source "$ROOT_DIR/lib/yes-no.sh" #source "$ROOT_DIR/lib/yes-no.sh"
source "$ROOT_DIR/lib/expired-date.sh"