Add ssl_mgmt script

This commit is contained in:
Thomas Preud'homme 2012-02-20 17:23:33 +01:00
parent 6c5525185c
commit 2b6d07e80b
3 changed files with 385 additions and 0 deletions

70
ssl_mgmt/README Normal file
View File

@ -0,0 +1,70 @@
ssl_mgmt is a helper to manage ssl certificate: creation, renewal and removal.
So far, only renewal is supported.
ssl_mgmt refers to certificates through the service they are associated with.
*** EXAMPLES ***
To renew the certificate associated to https, the command line is:
ssl_mgmt renew https
If you want to renew certificates of all services, you should do:
ssl_mgmt renew all
Note: This suppose that
* all services are listed in /root/homemade_certs;
* directories have special rights so that newly created certificates
automatically get proper rights;
* Root CA is already created
* openssl.cnf.in is copied at the root of the CA hierarchy
The file system hierarchy assumed is:
lrwxrwxrwx 1 root root 14 6 janv. 2010 certs -> /etc/ssl/certs
drws--S---+ 2 root ssl-cert 4096 23 janv. 2011 csr
-rw------- 1 root ssl-cert 1937 20 févr. 16:38 index.txt
-rw------- 1 root ssl-cert 20 20 févr. 16:38 index.txt.attr
drwSr-Sr--+ 2 root ssl-cert 4096 20 févr. 16:38 newcerts
drwSr-S---+ 2 root ssl-cert 4096 20 févr. 16:38 newkeys
-rw-r--r-- 1 root ssl-cert 1546 20 févr. 14:24 openssl.cnf.in
lrwxrwxrwx 1 root root 16 6 janv. 2010 private -> /etc/ssl/private
-rw------- 1 root ssl-cert 3 20 févr. 16:38 serial
About csr, newcerts and newkeys:
# file: usr/lib/ssl/CA/csr
# owner: root
# group: ssl-cert
# flags: ss-
user::rwx
group::---
other::---
default:user::rw-
default:group::r--
default:other::---
# file: usr/lib/ssl/CA/newcerts
# owner: root
# group: ssl-cert
# flags: ss-
user::rw-
group::r--
other::r--
default:user::rw-
default:group::r--
default:other::r--
# file: usr/lib/ssl/CA/newkeys
# owner: root
# group: ssl-cert
# flags: ss-
user::rw-
group::r--
other::---
default:user::rw-
default:group::r--
default:other::---
To use this script, you have to be root, or to be able to execute
commands with root privileges through sudo.
You should install it in a directory within the PATH of the root user,
such as /usr/local/sbin.

62
ssl_mgmt/openssl.cnf.in Normal file
View File

@ -0,0 +1,62 @@
#
# OpenSSL configuration file.
#
# Establish working directory
dir = .
[ ca ]
default_ca = CA_Default
[ CA_Default ]
serial = $dir/serial
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/certs/ca-cert.pem
private_key = $dir/private/ca-key.pem
default_days = #LENGTH# # Certificates are signed for default_days days
default_md = md5
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
policy = policy_match
copy_extensions = copy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 2048 # Taille des clés
default_keyfile = newkeys/key.pem # Nom de la clé généré (à spécifier en ligne de commande si différent)
default_md = md5 # Algorithme de résumé (hash)
string_mask = nombstr # Caractères authorisés
prompt = no
distinguished_name = req_distinguished_name
req_extensions = v3_req
# On ne veut ces extensions que pour générer les certificats racines
# donc on le spécifie sur la ligne de commande
x509_extensions = v3_ca
[ req_distinguished_name ]
organizationName = #ORG#
organizationalUnitName = #ORGUNIT#
localityName = #LOCALITY#
stateOrProvinceName = #STATE#
countryName = #COUNTRY#
commonName = #COMMONNAME#
[ v3_ca ]
basicConstraints = CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
subjectAltName = #ALTNAME#

253
ssl_mgmt/ssl_mgmt Executable file
View File

@ -0,0 +1,253 @@
#!/bin/sh
#
# ssl_mgmt, Copyright © 2012 Thomas Preud'homme
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# email_account is a helper to create e-mail accounts in a configuration
# using Postfix mail transport agent with vhosts and Cyrus IMAP server,
# in a Debian environment.
set -u
confFile=openssl.cnf
# Display usage.
usage ()
{
local - progname
progname=$1
echo "Usage :"
echo
echo "$progname renew <service>"
echo "$progname -h"
echo
echo "First form renew the certificate of the given service"
echo
echo "Second form prints this help."
}
# @param question Question to ask
# @return 0 if answer is positive, 1 else
#
# Ask question to the user with a default choice set to no.
ask_user_default_no ()
{
local - answer
answer="unset"
echo -n "$1 [y/N] "
while [ -n "$answer" -a "$answer" != "y" -a "$answer" != "Y" -a "$answer" != "n" -a "$answer" != "N" ]
do
read answer
if [ -z "$answer" -o "$answer" = "n" -o "$answer" = "N" ]
then
return 1
fi
if [ "$answer" = "y" -o "$answer" = "Y" ]
then
break
fi
echo -n "$2 [y/N] "
done
return 0
}
# Test number of argument is correct and their value are correct also.
test_args ()
{
local - user domain
while getopts "h" opt
do
case $opt in
"h")
if [ $# -gt 1 ]
then
echo "Error! Too many arguments." >&2
exit 1
fi
usage $(basename "$0")
exit 0 ;;
esac
done
if [ $# -ne 2 -o "$1" != "renew" ]
then
usage $(basename "$0")
exit 0
fi
eval service="\$$((OPTIND+1))"
}
# Are we root?
must_sudo ()
{
uid="$(id -u)"
[ ! $uid -eq 0 ]
return $?
}
# This function tries to become root with sudo and execute this script.
# NB: This function doesn't return.
try_sudo ()
{
local - ret
echo "You aren't root. Trying to use sudo to become root…"
sudo $0 "$@" # Try to execute the script with sudo
ret=$?
if [ ! $ret -eq 0 ]
then
echo "Error! You must be root or being able to become root by sudo without password to create an email account or add an email alias." >&2
fi
exit $ret
}
get_field_from_line ()
{
local - line field result
line="$1"
field="$2"
result="${line#*$field=}"
echo "${result%%/*}"
}
get_cert_params ()
{
local - subject issuer dates ext fromDate toDate
certFile="/etc/ssl/certs/${service}-cert.pem"
subject="$(openssl x509 -in "$certFile" -noout -subject)"
dates="$(openssl x509 -in "$certFile" -noout -dates)"
exclNoExt="-certopt no_header,no_version,no_serial,no_signame"
exclNoExt="$exclNoExt,no_validity,no_subject,no_issuer,no_pubkey"
exclNoExt="$exclNoExt,no_sigdump,no_aux"
altName="$(openssl x509 -in "$certFile" -text $exclNoExt | while read ext
do
if [ "$ext" = "X509v3 Subject Alternative Name:" ]
then
read altName
echo $altName
break
fi
done)"
country=$(get_field_from_line "$subject" "C")
state=$(get_field_from_line "$subject" "ST")
city=$(get_field_from_line "$subject" "L")
organization=$(get_field_from_line "$subject" "O")
unit=$(get_field_from_line "$subject" "OU")
commonName=$(get_field_from_line "$subject" "CN")
fromDate=${dates#*notBefore=}
fromDate=${fromDate%notAfter*}
fromDate=$(date -d "$fromDate" "+%s")
toDate=${dates#*notAfter=}
toDate=$(date -d "$toDate" "+%s")
days=$(($toDate-$fromDate))
days=$(($days/86400))
}
add_to_replace_cmd ()
{
local - replaceCmd key value
replaceCmd="$1"
key="$2"
value="$3"
if [ -n "$value" ]
then
echo "$replaceCmd${replaceCmd:+;}s/$key/$value/"
fi
}
generate_config ()
{
local - replaceCmd cnfTmpFile
replaceCmd="$(add_to_replace_cmd "${replaceCmd:-}" "#LENGTH#" "${days:-}")"
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#ORG#" "${organization:-}")"
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#ORGUNIT#" "${unit:-}")"
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#LOCALITY#" "${city:-}")"
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#STATE#" "${state:-}")"
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#COUNTRY#" "${country:-}")"
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#COMMONNAME#" "${commonName:-}")"
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#ALTNAME#" "${altName:-}")"
sed "$replaceCmd" $confFile.in > $confFile
if ask_user_default_no "Do you want to edit the openssl configuration file?"
then
if [ -z "${EDITOR:-}" ]
then
$EDITOR $confFile
else
editor $confFile
fi
fi
cnfTmpFile="$(mktemp --tmpdir=. openssl.cnf.XXXXXXXXXX)"
mv $confFile $cnfTmpFile
grep -v "#[A-Z]\+#" $cnfTmpFile > $confFile
rm $cnfTmpFile
}
generate_cert ()
{
openssl req -new -nodes -out csr/${service}-req.pem -keyout newkeys/${service}-key.pem -config $confFile
openssl req -in csr/${service}-req.pem -text -verify -noout
if ! ask_user_default_no "Is the Certificate Signing Request correct?"
then
return 1
fi
mv newkeys/${service}-key.pem private
openssl ca -batch -out newcerts/${service}-cert.pem -config $confFile -passin file:/root/passwords/root_ca -infiles csr/${service}-req.pem
mv newcerts/${service}-cert.pem certs
cat private/${service}-key.pem certs/${service}-cert.pem > private/${service}-keycert.pem
return 0
}
main ()
{
local - ret servicesok
ret=0
test_args "$@"
# This test should be useless if rights on this file are corrects
# (that is 770 for root:gt owner)
if must_sudo
then
try_sudo "$@"
fi
cd /usr/lib/ssl/CA/
if [ "${service}" = "all" ]
then
services=""
while read service
do
services="$services $service"
done </root/homemade-certs
else
services=${service}
fi
for service in $services
do
servicesok=""
get_cert_params
generate_config
if ! generate_cert
then
ret=1
else
servicesok="$servicesok${servicesok:+ }$service"
fi
done
echo "You should restart the following services: $servicesok"
return $ret
}
main "${@:-""}"
exit $?