#!/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 [-c] renew { | }" echo "$progname -h" echo echo "First form renew the certificate specified as a file or a service name" echo echo "Possible option:" echo echo "-c Only generate the configuration" 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 } # Parse arguments and test their number and value is correct. parse_args () { local - user domain action config_only="" while getopts "ch" opt do case $opt in "c") config_only=yes ;; "h") if [ $# -gt 1 ] then echo "Error! Too many arguments." >&2 exit 1 fi usage $(basename "$0") exit 0 ;; esac done eval action="\${$OPTIND:-}" if [ $(($#-$OPTIND+1)) -ne 2 -o "$action" != "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=}" if [ "$result" != "$line" ] then echo "${result%%/*}" fi } get_cert_params () { local - subject issuer dates ext fromDate toDate certPath certPath="$1" subject="$(openssl x509 -in "$certPath" -noout -subject)" dates="$(openssl x509 -in "$certPath" -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 "$certPath" -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" echo "$replaceCmd${replaceCmd:+;}s/$key/${value:-}/" } 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:-}")" cnfTmpFile="$(mktemp --tmpdir=. openssl.cnf.XXXXXXXXXX)" sed "$replaceCmd" $confFile.in > $cnfTmpFile if ask_user_default_no "Do you want to edit the openssl configuration file?" then if [ -n "${EDITOR:-}" ] then $EDITOR $cnfTmpFile else editor $cnfTmpFile fi fi mv $cnfTmpFile $confFile } generate_cert () { local - service certPath keyPath reqFile certFile keyFile keycertFile service="$1" certPath="$2" keyPath="$3" reqFile=${service}-req.pem certFile=${certPath##*/} keyFile=${keyPath##*/} keycertFile=${service}-keycert.pem openssl req -new -nodes -out csr/$reqFile -keyout newkeys/$keyFile -config $confFile openssl req -in csr/$reqFile -text -verify -noout if ! ask_user_default_no "Is the Certificate Signing Request correct?" then return 1 fi mv newkeys/$keyFile private openssl ca -batch -out newcerts/$certFile -config $confFile -passin file:/root/passwords/root_ca -infiles csr/$reqFile mv newcerts/$certFile certs cat private/$keyFile certs/$certFile > private/$keycertFile return 0 } main () { local - ret servicesok certPath keyPath ret=0 parse_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