#!/bin/bash

### SSL/TLS DOMAINS GENERATOR 0.3 [MAJ 26]
### Installation SSL/TLS pour APACHE (ou autre application supportant TLS)
### Création d'un mot de passe pour la génération des certificats
### Création d'une clé et d'une demande de certification pour le serveur
### Création d'une autorité de certification et signature du certificat (v3)
### Cool (: !!!

#Identité de l'autorité de certification par défaut :
CAname="CA_DEV_Local"
CAcie="Certificat SSL"
CAuname="Local DEV Certification Authority"
pays="FR"

#Nom des fichiers par défaut pour le serveur et les sous-domaines :
defo_server=server
defo_domains=domains

#Couleurs sur la console :
blanc=`tput setaf 7`
rouge=`tput setaf 1`
vert=`tput setaf 2`
jaune=`tput setaf 3`
bleu=`tput setaf 4`
bld=`tput bold`
reset=`tput sgr0`
ms="${bld}${vert}OPENSSL ==> ${reset}"

### FONCTIONS ###

tmpfile=tmp.conf

function creat_SSLconf {

  if [ $1 == v1 ]; then
    echo -e "[req]\ndefault_bits=2048\nprompt=no\ndefault_md=sha256\ndistinguished_name=dn" > $tmpfile
    echo -e "[dn]\nC=$pays\nO=$2\nOU=$3\nCN=$4" >> $tmpfile
  fi

  if [ $1 == v2 ]; then
    echo -e "authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE" > $tmpfile
    echo "keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment" >> $tmpfile
    echo -e "subjectAltName=@alt_names\n" >> $tmpfile
    echo -e "[alt_names]\nDNS.1=$2" >> $tmpfile
  fi

}

#Fonction pour déterminer la validité d'un nom de domaine avec un wildcard en option
#Exemple : *.sio.local, www.sio.local, sio.local :
function isdom {
 for d in "$1"; do
  [[ $d =~ \
     ^((\*|[\w\d]+(-[\w\d]+)*)\.)*[a-zA-Z](-?[a-zA-Z0-9])+\.[a-zA-Z]{2,}$ \
  ]] && return 0 || return 1
 done
}

#debug :
 #if isdom "*.sio.local"; then
  #echo "TRUE"
  #else echo "FALSE"
 #fi

function creat_request {

 if [ ! -z "$2"  ] &&  [ "$2" == "subdom" ] && [ ! -z "$newdom" ]; then

  newdom="*.$newdom"

 else

    read -rp "Saisir un nom de domaine principal ${bld}${jaune}valide${reset} (ex. monsite.com) : " newdom

    read -rp "${bld}OPTION${reset} : Saisir un nom principal (ex. Ma société) : " name1
    if [ -z "$name1" ]; then name1="AGlobal SSL WebSite"; fi

    read -rp "${bld}OPTION${reset} : Saisir un nom secondaire (ex. Mon petit nom) : " name2
    if [ -z "$name2" ]; then name2="Free SSL for All"; fi

    export newdom="$newdom"
    export name1="$name1"
    export name2="$name2"

 fi

  if isdom "$newdom" &&  [ ! -z $newdom ]; then

    echo $ms"Création de la demande de certificat : ${bld}$1.csr${reset}"

    creat_SSLconf v1 "$name1" "$name2" "$newdom"
    openssl req -new -sha256 -nodes -key private.key -out $1.csr -config <( cat $tmpfile )
    rm $tmpfile
    creat_SSLconf v2 "$newdom"

  else

    IFS='.' read -r -a dot <<< "$newdom"

    for index in "${!dot[@]}"; do
      totdot=$((totdot+1))
    done

    if [ $totdot > 2 ]; then
      echo "${bld}${rouge}ATTENTION${reset} : vous utilisez pour ce certificat un sous-domaine [${bld}${rouge}${dot[0]}${reset}]"
      echo "Le domaine principal doit être de type : ${bld}${vert}domaine.tdl${reset} ou ${bld}${vert}www.domaine.tld${reset}"
      echo "Les sous-domaines de type ${bld}${jaune}sub.domaine.tld${reset} seront automatiquement crées par un wildcard [*]"
      reset
    fi

    echo "${bld}${rouge}Le nom de domaine principal doit être renseigné !${reset}"
    reset

  fi

}

function sign {

echo $ms"Signature du certificat : ${bld}$1.crt${reset}"

openssl x509 -req -in $1.csr -CA public.crt -CAkey public.key -CAcreateserial \
-CAserial public.srl -passin file:.passkey -out $1.crt -days 3652 -sha256 -extfile $tmpfile

rm $1.csr
rm $tmpfile

}

function reset {
export reqfile=''
export newdom=''
export name1=''
export name2=''
cd $curdir
exit 0
}

#####################################################################################

echo "${bld}${jaune}### GESTION SSL/TLS ###${reset}"

if [ "$EUID" -ne 0 ]; then
  echo "[${bld}${rouge}sudo su${reset}] Ce script doit être executé comme super utilisateur !"
  reset
fi

#Repertoire par défaut d'installation des certificats et des clés :
curdir=$(pwd)
defdir=./ssl
ssldir=$defdir
opt="${bld}${blanc}OPTION : ${reset}"

if [ ! -d $ssldir ] && [ ! -f $ssldir/public.key ]; then

  echo $opt"Saisir un chemin vers le dossier ssl (ex. /etc/apache2/ssl)"
  read -rp "Par défaut un dossier 'ssl' sera crée au même emplacement : " ssldir

  if [ -z $ssldir ]; then ssldir=$defdir; fi
  if [ ! -d $ssldir ]; then mkdir $ssldir; fi

fi

cd $ssldir

if [ -f private.key ] && [ -f public.key ]; then

  echo "Les clés privée et publique existent déjà."
  read -rp "Voulez-vous créer un nouveau certificat ? (o) : " quest

  if [ "$quest" == "o" ]; then

    read -rp "Nom du nouveau certificat (ex. pour Apache) : " newcname
    if [ ! -z $newcname ]; then reqfile=$newcname; else echo "${bld}${rouge}Nom invalide !${reset}"; reset; fi

    echo $ms"Création du fichier de demande de certificat : ${bld}$reqfile.csr${reset}"
    creat_request $reqfile
    sign $reqfile
    reset

  else

    quest=''
    read -rp "Voulez-vous recréer les clés et les certificats par défaut ? (o) : " quest
      if [ "$quest" == "o" ]; then

        quest=''; path=$(pwd)
        echo "${bld}${jaune}### ATTENTION ###${reset} Ceci va effacer l'ensemble du dossier : ${bld}$path${reset}"
        read -rp "Continuer ? (o) : " quest
        if [ "$quest" == "o" ]; then rm ./*; else echo "Annulé."; reset; fi

      else

        echo "Annulé."; reset

      fi

  fi

fi


echo $ms"Création d'un mot de passe aléatoire dans le fichier : ${bld}.passkey${reset}"
openssl rand -out .passkey 16

echo $ms"Création de la clé privée : ${bld}private.key${reset}"
openssl genrsa 2048 > private.key

reqfile=$defo_server

echo $ms"Création du fichier de demande de certificat : ${bld}$reqfile.csr${reset}"
creat_request $reqfile

echo $ms"Création de la clé publique : ${bld}public.key${reset}"
openssl genrsa -des3 -passout file:.passkey 2048 > public.key

echo

echo $ms"Création du certificat d'autorité (CA) : ${bld}public.crt${reset}"
openssl req -new -x509 -days 3652 -key public.key -out public.crt -passin file:.passkey \
-subj "/C=$pays/O=$CAcie/OU=$CAuname/CN=$CAname"

sign $reqfile

echo

echo $ms"Creation d'une demande de certification pour les sous-domaines : ${bld}*.$newdom${reset}"

reqfile=$defo_domains
creat_request $reqfile subdom

sign $reqfile

newdom=''
nane1=''
name2=''

echo
echo "${bld}${vert}### SUCCES ! ###${reset}"
echo -e "\nContenu du dossier : $ssldir ==>${bld}${bleu}"

ls

echo
echo "${reset}${bld}${vert}### INFOS IMPORTANTES A CONSERVER ###${reset}"
echo "${bld}domains.crt${reset} ==> Certificat pour les ${bld}sous-domaines${reset} de type ${bld}xxx.domaine.tld${reset} (pour la conf ssl d'Apache par exemple)."
echo "${bld}private.key${reset} ==> Clé privée pour le serveur (pour la conf ssl d'Apache par exemple) à conserver pour la génération des certificats."
echo "${bld}public.crt${reset} ==> Certificat à distribuer et à installer manuellement sur un client (Windows, Firefox,...)."
echo "${bld}public.key${reset} ==> Clé publique à conserver pour générer de nouveaux certificats."
echo "${bld}public.srl${reset} ==> N° de serie pour la génération des certificats."
echo "${bld}server.crt${reset} ==> Certificat pour le ${bld}serveur${reset} de type ${bld}domaine.tld${reset} (pour la conf ssl d'Apache par exemple)."
echo
echo "Pour plus d'info, lancer la commande :"
echo "${bld}${jaune}openssl x509 -text -in $ssldir/server.crt -noout${reset}"
echo "pour la verification du certificat du domaine principal."
echo "OU :"
echo "${bld}${jaune}openssl x509 -text -in $ssldir/domains.crt -noout${reset}"
echo "pour la verification du certificat des sous-domaines."
echo

cd $curdir

