Compare commits

..

3 commits
dev ... master

5 changed files with 39 additions and 178 deletions

View file

@ -12,44 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
* Fix mode of shellpki script in README file when installing it
### Removed ### Removed
### Security ### Security
## [22.12.2] 2022-12-13
### Changed
* Defaults default_crl_days to 2 years instead of 1
### Fixed
* Fix ${CRL} and ${CA_DIR} rights so that CRL file can be read by openvpn
## [22.12.1] 2022-12-02
### Fixed
* cert-expirations.sh: check CARP state only when checking ca and certs expirations
* Fix path variables in cert-expirations.sh
## [22.12] 2022-12-01
### Added
* The key file can be read and written only by the owner
### Changed
* Use genpkey and pkey instead of genrsa and rsa
* Improved cert-expirations.sh for better readability of its ouput
### Fixed
* Create index.txt.attr file
## [22.04] 2022-04-14 ## [22.04] 2022-04-14
### Added ### Added

View file

@ -16,7 +16,7 @@ be copied to [ansible-roles/openvpn](https://gitea.evolix.org/evolix/ansible-rol
useradd shellpki --system -M --home-dir /etc/shellpki --shell /usr/sbin/nologin useradd shellpki --system -M --home-dir /etc/shellpki --shell /usr/sbin/nologin
mkdir /etc/shellpki mkdir /etc/shellpki
install -m 0640 openssl.cnf /etc/shellpki/ install -m 0640 openssl.cnf /etc/shellpki/
install -m 0750 shellpki /usr/local/sbin/shellpki install -m 0755 shellpki /usr/local/sbin/shellpki
chown -R shellpki: /etc/shellpki chown -R shellpki: /etc/shellpki
~~~ ~~~
@ -31,7 +31,7 @@ chown -R shellpki: /etc/shellpki
useradd -r 1..1000 -d /etc/shellpki -s /sbin/nologin _shellpki useradd -r 1..1000 -d /etc/shellpki -s /sbin/nologin _shellpki
mkdir /etc/shellpki mkdir /etc/shellpki
install -m 0640 openssl.cnf /etc/shellpki/ install -m 0640 openssl.cnf /etc/shellpki/
install -m 0750 shellpki /usr/local/sbin/shellpki install -m 0755 shellpki /usr/local/sbin/shellpki
chown -R _shellpki:_shellpki /etc/shellpki chown -R _shellpki:_shellpki /etc/shellpki
~~~ ~~~

View file

@ -1,126 +1,28 @@
#!/bin/sh #!/bin/sh
VERSION="22.12.1" VERSION="22.04"
show_version() { carp=$(/sbin/ifconfig carp0 2>/dev/null | grep 'status' | cut -d' ' -f2)
cat <<END
cert-expirations.sh version ${VERSION}
Copyright 2020-2022 Evolix <info@evolix.fr>, if [ "$carp" = "backup" ]; then
Jérémy Lecour <jlecour@evolix.fr>, exit 0
Jérémy Dubois <jdubois@evolix.fr> fi
and others.
cert-expirations.sh comes with ABSOLUTELY NO WARRANTY. This is free software, echo "Warning : all times are in UTC !\n"
and you are welcome to redistribute it under certain conditions.
See the MIT Licence for details.
END
}
show_usage() { echo "CA certificate:"
cat <<END openssl x509 -enddate -noout -in /etc/shellpki/cacert.pem \
Usage: ${0} [--version] | cut -d '=' -f 2 \
END | sed -e "s/^\(.*\)\ \(20..\).*/- \2 \1/"
}
check_carp_state() { echo ""
if [ "${SYSTEM}" = "openbsd" ]; then
carp=$(/sbin/ifconfig carp0 2>/dev/null | grep 'status' | cut -d' ' -f2)
if [ "$carp" = "backup" ]; then echo "Client certificates:"
exit 0 cat /etc/shellpki/index.txt \
fi | grep ^V \
fi | awk -F "/" '{print $1,$5}' \
} | awk '{print $2,$5}' \
| sed 's/CN=//' \
check_ca_expiration() { | sed -E 's/([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})Z (.*)/- 20\1 \2 \3 \4:\5:\6 \7/' \
echo "CA certificate:" | awk '{if ($3 == "01") $3="Jan"; else if ($3 == "02") $3="Feb"; else if ($3 == "03") $3="Mar"; else if ($3 == "04") $3="Apr"; else if ($3 == "05") $3="May"; else if ($3 == "06") $3="Jun"; else if ($3 == "07") $3="Jul"; else if ($3 == "08") $3="Aug"; else if ($3 == "09") $3="Sep"; else if ($3 == "10") $3="Oct"; else if ($3 == "11") $3="Nov"; else if ($3 == "12") $3="Dec"; print $0;}' \
openssl x509 -enddate -noout -in ${cacert_path} \ | sort -n -k 2 -k 3M -k 4
| cut -d '=' -f 2 \
| sed -e "s/^\(.*\)\ \(20..\).*/- \2 \1/"
}
check_certs_expiration() {
# Syntax "cmd | { while read line; do var="foo"; done echo $var }" needed, otherwise $var is empty at the end of while loop
grep ^V ${index_path} \
| awk -F "/" '{print $1,$5}' \
| awk '{print $2,$5}' \
| sed 's/CN=//' \
| sed -E 's/([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})Z (.*)/- 20\1 \2 \3 \4:\5:\6 \7/' \
| awk '{if ($3 == "01") $3="Jan"; else if ($3 == "02") $3="Feb"; else if ($3 == "03") $3="Mar"; else if ($3 == "04") $3="Apr"; else if ($3 == "05") $3="May"; else if ($3 == "06") $3="Jun"; else if ($3 == "07") $3="Jul"; else if ($3 == "08") $3="Aug"; else if ($3 == "09") $3="Sep"; else if ($3 == "10") $3="Oct"; else if ($3 == "11") $3="Nov"; else if ($3 == "12") $3="Dec"; print $0;}' \
| sort -n -k 2 -k 3M -k 4 | {
while read -r line; do
# Predicting expirations - OpenBSD case (date is not the same than in Linux)
if [ "${SYSTEM}" = "openbsd" ]; then
# Already expired if expiration date is before now
if [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -le "$(date +%s)" ]; then
expired_certs="${expired_certs}$line\n"
# Expiring soon if expiration date is after now and before now + $somedays days
elif [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -gt "$(date +%s)" ] && [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -lt "$(($(date +%s) + somedays))" ]; then
expiring_soon_certs="${expiring_soon_certs}$line\n"
# Still valid for a time if expiration date is after now + $somedays days
elif [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -ge "$(($(date +%s) + somedays))" ]; then
still_valid_certs="${still_valid_certs}$line\n"
fi
# Non OpenBSD cases
else
# Already expired if expiration date is before now
if [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -le "$(date +%s)" ]; then
expired_certs="${expired_certs}$line\n"
# Expiring soon if expiration date is after now and before now + $somedays days
elif [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -gt "$(date +%s)" ] && [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -lt "$(($(date +%s) + somedays))" ]; then
expiring_soon_certs="${expiring_soon_certs}$line\n"
# Still valid for a time if expiration date is after now + $somedays days
elif [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -ge "$(($(date +%s) + somedays))" ]; then
still_valid_certs="${still_valid_certs}$line\n"
fi
fi
done
echo "Expired client certificates:"
echo "${expired_certs}"
echo "Valid client certificates expiring soon (in less than $((somedays / 60 / 60 / 24)) days):"
echo "${expiring_soon_certs}"
echo "Valid client certificates expiring later (in more than $((somedays / 60 / 60 / 24)) days):"
echo "${still_valid_certs}"
}
}
main() {
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
cacert_path="/etc/shellpki/cacert.pem"
index_path="/etc/shellpki/index.txt"
somedays="3456000" # 40 days currently
expired_certs=""
expiring_soon_certs=""
still_valid_certs=""
case "$1" in
version|--version)
show_version
exit 0
;;
help|--help)
show_usage
exit 0
;;
"")
check_carp_state
echo "Warning : all times are in UTC !"
echo ""
check_ca_expiration
echo ""
check_certs_expiration
;;
*)
show_usage >&2
exit 1
;;
esac
}
main "$@"

View file

@ -1,4 +1,4 @@
# VERSION="22.12.2" # VERSION="22.04"
[ ca ] [ ca ]
default_ca = CA_default default_ca = CA_default
@ -14,7 +14,7 @@ crl = $dir/crl.pem
private_key = $dir/cakey.key private_key = $dir/cakey.key
RANDFILE = $dir/.rand RANDFILE = $dir/.rand
default_days = 365 default_days = 365
default_crl_days= 730 default_crl_days= 365
default_md = sha256 default_md = sha256
preserve = no preserve = no
policy = policy_match policy = policy_match

View file

@ -5,7 +5,7 @@
set -u set -u
VERSION="22.12.2" VERSION="22.04"
show_version() { show_version() {
cat <<END cat <<END
@ -137,14 +137,14 @@ warning() {
} }
verify_ca_password() { verify_ca_password() {
"${OPENSSL_BIN}" pkey \ "${OPENSSL_BIN}" rsa \
-in "${CA_KEY}" \ -in "${CA_KEY}" \
-passin pass:"${CA_PASSWORD}" \ -passin pass:"${CA_PASSWORD}" \
>/dev/null 2>&1 >/dev/null 2>&1
} }
get_real_path() { get_real_path() {
# --canonicalize is supported on Linux # --canonicalize is supported on Linux
# -f is supported on Linux and OpenBSD # -f is supported on Linux and OpenBSD
readlink -f -- "${1}" readlink -f -- "${1}"
} }
@ -224,10 +224,9 @@ replace_existing_or_abort() {
init() { init() {
umask 0177 umask 0177
[ -d "${CA_DIR}" ] || mkdir -m 0751 "${CA_DIR}" [ -d "${CA_DIR}" ] || mkdir -m 0750 "${CA_DIR}"
[ -d "${CRT_DIR}" ] || mkdir -m 0750 "${CRT_DIR}" [ -d "${CRT_DIR}" ] || mkdir -m 0750 "${CRT_DIR}"
[ -f "${INDEX_FILE}" ] || touch "${INDEX_FILE}" [ -f "${INDEX_FILE}" ] || touch "${INDEX_FILE}"
[ -f "${INDEX_FILE}.attr" ] || touch "${INDEX_FILE}.attr"
[ -f "${CRL}" ] || touch "${CRL}" [ -f "${CRL}" ] || touch "${CRL}"
[ -f "${SERIAL}" ] || echo "01" > "${SERIAL}" [ -f "${SERIAL}" ] || echo "01" > "${SERIAL}"
@ -279,18 +278,17 @@ init() {
passout_arg="" passout_arg=""
if [ -n "${CA_PASSWORD:-}" ]; then if [ -n "${CA_PASSWORD:-}" ]; then
passout_arg="-pass pass:${CA_PASSWORD}" passout_arg="-passout pass:${CA_PASSWORD}"
elif [ "${non_interactive}" -eq 1 ]; then elif [ "${non_interactive}" -eq 1 ]; then
error "In non-interactive mode, you must pass CA_PASSWORD as environment variable." error "In non-interactive mode, you must pass CA_PASSWORD as environment variable."
fi fi
if [ ! -f "${CA_KEY}" ]; then if [ ! -f "${CA_KEY}" ]; then
"${OPENSSL_BIN}" genpkey \ "${OPENSSL_BIN}" genrsa \
-algorithm RSA \
-out "${CA_KEY}" \ -out "${CA_KEY}" \
${passout_arg} \ ${passout_arg} \
-aes256 \ -aes256 \
-pkeyopt "rsa_keygen_bits:${CA_KEY_LENGTH}" \ "${CA_KEY_LENGTH}" \
>/dev/null 2>&1 >/dev/null 2>&1
# shellcheck disable=SC2181 # shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -357,10 +355,9 @@ ocsp() {
port=$(echo "${ocsp_uri}" | cut -d':' -f2) port=$(echo "${ocsp_uri}" | cut -d':' -f2)
if [ ! -f "${OCSP_KEY}" ]; then if [ ! -f "${OCSP_KEY}" ]; then
"${OPENSSL_BIN}" genpkey \ "${OPENSSL_BIN}" genrsa \
-algorithm RSA \
-out "${OCSP_KEY}" \ -out "${OCSP_KEY}" \
-pkeyopt "rsa_keygen_bits:${KEY_LENGTH}" \ "${KEY_LENGTH}" \
>/dev/null 2>&1 >/dev/null 2>&1
# shellcheck disable=SC2181 # shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -683,19 +680,17 @@ create() {
# generate private key # generate private key
pass_args="" pass_args=""
if [ -n "${password_file:-}" ]; then if [ -n "${password_file:-}" ]; then
pass_args="-aes256 -pass file:${password_file}" pass_args="-aes256 -passout file:${password_file}"
elif [ -n "${PASSWORD:-}" ]; then elif [ -n "${PASSWORD:-}" ]; then
pass_args="-aes256 -pass pass:${PASSWORD}" pass_args="-aes256 -passout pass:${PASSWORD}"
fi fi
"${OPENSSL_BIN}" genpkey \ "${OPENSSL_BIN}" genrsa \
-algorithm RSA \
-out "${key_file}" \ -out "${key_file}" \
${pass_args} \ ${pass_args} \
-pkeyopt "rsa_keygen_bits:${KEY_LENGTH}" \ "${KEY_LENGTH}" \
>/dev/null 2>&1 >/dev/null 2>&1
# shellcheck disable=SC2181 # shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then if [ "$?" -eq 0 ]; then
chmod 600 "${key_file}"
echo "The KEY file is available at \`${key_file}'" echo "The KEY file is available at \`${key_file}'"
else else
error "Error generating the private key" error "Error generating the private key"
@ -1103,11 +1098,9 @@ main() {
# fix right # fix right
chown -R "${PKI_USER}":"${PKI_USER}" "${CA_DIR}" chown -R "${PKI_USER}":"${PKI_USER}" "${CA_DIR}"
chmod 750 "${CRT_DIR}" "${KEY_DIR}" "${CSR_DIR}" "${PKCS12_DIR}" "${OVPN_DIR}" "${TMP_DIR}" chmod 750 "${CA_DIR}" "${CRT_DIR}" "${KEY_DIR}" "${CSR_DIR}" "${PKCS12_DIR}" "${OVPN_DIR}" "${TMP_DIR}"
chmod 600 "${INDEX_FILE}"* "${SERIAL}"* "${CA_KEY}" chmod 600 "${INDEX_FILE}"* "${SERIAL}"* "${CA_KEY}" "${CRL}"
chmod 640 "${CA_CERT}" chmod 640 "${CA_CERT}"
chmod 604 "${CRL}"
chmod 751 "${CA_DIR}"
} }
main "$@" main "$@"