#!/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 . # # 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 " 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