239 lines
6.1 KiB
Bash
Executable file
239 lines
6.1 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# shellpki is a wrapper around openssl to manage a small PKI
|
|
#
|
|
|
|
init() {
|
|
umask 0177
|
|
|
|
if [ -f "${CADIR}/private.key" ]; then
|
|
echo "${CADIR}/private.key already exists, do you really want to erase it ?\n"
|
|
echo "Press return to continue..."
|
|
read -r REPLY
|
|
fi
|
|
|
|
[ -d "${CADIR}" ] || mkdir -pm 0700 "${CADIR}"
|
|
[ -d "${CADIR}/certs" ] || mkdir -m 0777 "${CADIR}/certs"
|
|
[ -d "${CADIR}/tmp" ] || mkdir -m 0700 "${CADIR}/tmp"
|
|
[ -f "${CADIR}/index.txt" ] || touch "${CADIR}/index.txt"
|
|
[ -f "${CADIR}/serial" ] || echo "01" > "${CADIR}/serial"
|
|
|
|
"${OPENSSL}" req \
|
|
-config "${CONFFILE}" \
|
|
-newkey rsa:4096 -sha512 \
|
|
-x509 -days 3650 \
|
|
-extensions v3_ca \
|
|
-keyout "${CADIR}/private.key" \
|
|
-out "${CADIR}/cacert.pem"
|
|
}
|
|
|
|
check_cn() {
|
|
cn="${1}"
|
|
if [ -f "${CADIR}/certs/${cn}.crt" ]; then
|
|
echo "Please revoke actual ${cn} cert before creating one"
|
|
echo
|
|
echo "Press return to continue..."
|
|
read -r REPLY
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
create() {
|
|
umask 0137
|
|
echo "Please enter your CN (Common Name)"
|
|
read -r cn
|
|
echo
|
|
echo "Your CN is '${cn}'"
|
|
echo "Press return to continue..."
|
|
read -r REPLY
|
|
echo
|
|
|
|
# check if CN already exist
|
|
check_cn "${cn}"
|
|
|
|
# generate private key
|
|
echo "Should private key be protected by a passphrase? [y/N] "
|
|
read -r REPLY
|
|
if [ "$REPLY" = "y" ] || [ "$REPLY" = "Y" ]; then
|
|
"$OPENSSL" genrsa -aes256 -out "${KEYDIR}/${cn}-${TIMESTAMP}.key" 2048
|
|
else
|
|
"$OPENSSL" genrsa -out "${KEYDIR}/${cn}-${TIMESTAMP}.key" 2048
|
|
fi
|
|
|
|
# generate csr req
|
|
"$OPENSSL" req -batch \
|
|
-new \
|
|
-key "${KEYDIR}/${cn}-${TIMESTAMP}.key" \
|
|
-out "${CSRDIR}/${cn}-${TIMESTAMP}.csr" \
|
|
-config /dev/stdin <<EOF
|
|
$(cat "${CONFFILE}")
|
|
commonName_default = ${cn}
|
|
EOF
|
|
|
|
# ca sign and generate cert
|
|
"${OPENSSL}" ca \
|
|
-config "${CONFFILE}" \
|
|
-in "${CSRDIR}/${cn}-${TIMESTAMP}.csr" \
|
|
-out "${CADIR}/certs/${cn}.crt"
|
|
|
|
# generate pem format
|
|
cat "${CADIR}/certs/${cn}.crt" "${CADIR}/cacert.pem" "${KEYDIR}/${cn}-${TIMESTAMP}.key" >> "${PEMDIR}/${cn}-${TIMESTAMP}.pem"
|
|
|
|
# generate pkcs12 format
|
|
openssl pkcs12 -export -nodes -passout pass: -inkey "${KEYDIR}/${cn}-${TIMESTAMP}.key" -in "${CADIR}/certs/${cn}.crt" -out "${PKCS12DIR}/${cn}-${TIMESTAMP}.p12"
|
|
|
|
# generate openvpn format
|
|
if [ -e "${PREFIX}/ovpn.conf" ]; then
|
|
cat "${PREFIX}/ovpn.conf" > "${OVPNDIR}/${cn}-${TIMESTAMP}.ovpn" <<EOF
|
|
<ca>
|
|
$(cat "${CADIR}/cacert.pem")
|
|
</ca>
|
|
|
|
<cert>
|
|
$(cat "${CADIR}/certs/${cn}.crt")
|
|
</cert>
|
|
|
|
<key>
|
|
$(cat "${KEYDIR}/${cn}-${TIMESTAMP}.key")
|
|
</key>
|
|
EOF
|
|
echo "The configuration file is available in ${OVPNDIR}/${cn}.ovpn"
|
|
fi
|
|
}
|
|
|
|
fromcsr() {
|
|
echo "Please enter path for your CSR request file"
|
|
read -r path
|
|
echo
|
|
|
|
if [ ! -e "${path}" ]; then
|
|
echo "Error in path..." >&2
|
|
echo >&2
|
|
echo "Press return to continue..." >&2
|
|
read -r REPLY
|
|
exit 1
|
|
fi
|
|
|
|
path=$(readlink -f "${path}")
|
|
|
|
# get CN from CSR
|
|
cn=$(openssl req -noout -subject -in "${path}"|grep -Eo "CN=[^/]*"|cut -d'=' -f2)
|
|
|
|
# check if CN already exist
|
|
check_cn "${cn}"
|
|
|
|
# copy CSR to CSRDIR
|
|
cp "$path" "${CSRDIR}/${cn}-${TIMESTAMP}.csr"
|
|
|
|
# ca sign and generate cert
|
|
"${OPENSSL}" ca \
|
|
-config "${CONFFILE}" \
|
|
-in "${CSRDIR}/${cn}-${TIMESTAMP}.csr" \
|
|
-out "${CADIR}/certs/${cn}.crt"
|
|
}
|
|
|
|
revoke() {
|
|
echo "Please enter CN (Common Name) to revoke"
|
|
read -r cn
|
|
echo
|
|
echo "CN '${cn}' will be revoked"
|
|
echo "Press return to continue..."
|
|
read -r REPLY
|
|
echo
|
|
|
|
[ ! -f "${CADIR}/certs/${cn}.crt" ] && echo "Unknow CN : ${cn}" >&2 && exit 1
|
|
|
|
echo "Revoke certificate ${CADIR}/certs/${cn}.crt :"
|
|
"$OPENSSL" ca \
|
|
-config "${CONFFILE}" \
|
|
-revoke "${CADIR}/certs/${cn}.crt" \
|
|
&& rm "${CADIR}/certs/${cn}.crt"
|
|
|
|
echo "Update CRL :"
|
|
"$OPENSSL" ca \
|
|
-config "${CONFFILE}" \
|
|
-gencrl -out "${CADIR}/crl.pem"
|
|
}
|
|
|
|
list() {
|
|
echo "* List of allowed CN :"
|
|
ls -1 "${CADIR}/certs"
|
|
}
|
|
|
|
main() {
|
|
if [ "$(id -u)" != "0" ]; then
|
|
echo "Please become root before running ${0##*/}!" >&2
|
|
echo >&2
|
|
echo "Press return to continue..." >&2
|
|
read -r REPLY
|
|
exit 1
|
|
fi
|
|
|
|
# main vars
|
|
PREFIX="/etc/shellpki"
|
|
PKIUSER="shellpki"
|
|
CONFFILE="${PREFIX}/openssl.cnf"
|
|
CADIR=$(grep -E "^dir" "${CONFFILE}" | cut -d'=' -f2|xargs -n1)
|
|
OPENSSL=$(command -v openssl)
|
|
TIMESTAMP=$(/bin/date +"%s")
|
|
# directories for clients key, csr, crt
|
|
KEYDIR="${PREFIX}/private"
|
|
CSRDIR="${PREFIX}/requests"
|
|
PEMDIR="${PREFIX}/pem"
|
|
PKCS12DIR="${PREFIX}/pkcs12"
|
|
OVPNDIR="${PREFIX}/openvpn"
|
|
|
|
if ! getent passwd "${PKIUSER}" >/dev/null || ! getent group "${PKIUSER}" >/dev/null; then
|
|
echo "You must create ${PKIUSER} user and group !" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -e "${CONFFILE}" ]; then
|
|
echo "${CONFFILE} is missing" >&2
|
|
>&2
|
|
echo "Press return to continue..." >&2
|
|
read -r REPLY
|
|
exit 1
|
|
fi
|
|
|
|
# create needed dir
|
|
[ -d "${PREFIX}" ] || mkdir -p "${PREFIX}"
|
|
[ -d "${KEYDIR}" ] || mkdir -m 0750 "${KEYDIR}"
|
|
[ -d "${CSRDIR}" ] || mkdir -m 0755 "${CSRDIR}"
|
|
[ -d "${PEMDIR}" ] || mkdir -m 0750 "${PEMDIR}"
|
|
[ -d "${PKCS12DIR}" ] || mkdir -m 0750 "${PKCS12DIR}"
|
|
[ -d "${OVPNDIR}" ] || mkdir -m 0750 "${OVPNDIR}"
|
|
|
|
# fix right
|
|
find "${PREFIX}" ! -path "${CADIR}" -exec chown "${PKIUSER}":"${PKIUSER}" {} \; -exec chmod u=rwX,g=rX,o= {} \;
|
|
|
|
case "$1" in
|
|
init)
|
|
init
|
|
;;
|
|
|
|
create)
|
|
create
|
|
;;
|
|
|
|
fromcsr)
|
|
fromcsr
|
|
;;
|
|
|
|
revoke)
|
|
revoke
|
|
;;
|
|
|
|
list)
|
|
list
|
|
;;
|
|
|
|
*)
|
|
echo "Usage: ${0} {init|create|fromcsr|revoke|list}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|