254 lines
6.2 KiB
Bash
Executable File
254 lines
6.2 KiB
Bash
Executable File
#!/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 $?
|