#!/bin/sh
#
###############################################################################
# Copyright (c) 2005, Marcel Stritzelberger, computing comptence
# All rights reserved.
#
# Redistribution and use in source and binary forms, 
# with or without modification, are permitted provided that the following 
# conditions are met:
#
# Redistributions of source code must retain the above copyright notice, 
# this list of conditions and the following disclaimer.
# Redistributions in binary form must reproduce the above copyright notice, 
# this list of conditions and the following disclaimer in the documentation 
# and/or other materials provided with the distribution.
# Neither the name of the computing comptence nor the names of its contributors may
# be used to endorse or promote products derived from this software without 
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE,
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
###############################################################################


###############################################################################
# WICHTIGE GRUNDEINSTELLUNGEN! Bitte Anpassen!
###############################################################################
# Firmenname des Skriptherstellers
COMPANY="computing competence"
# Firmenname fü das CA Zertifikat 
CACOMPANY="computing comptence"
CACOMPANYCOUNTRY="de"
CACOMPANYEMAIL="info@computing-competence"
CACOMPANYSTATE="nrw"
CACOMPANYTOWN="erkrath"
# Firmenname für die Zertifikate
CERTCOMPANY="bsdbox"
CERTCOMPANYCOUNTRY="de"
CERTCOMPANYSTATE="nrw"
CERTCOMPANYTOWN="erkrath"

# Pfad wo das Skript liegt (ohne / am Ende)
INSTALLPATH=`pwd`
# Wohin soll vorhandenes gesichert werden? (ohne / am Ende)
BACKUPDIR=$INSTALLPATH/backup
# Wohin soll Protokolliert werden?
INSTALLLOG=$INSTALLPATH/install.log

### Zertifikatseinstellungen
# Wie lange soll das CA Zertifikat gültig sein? (In Tagen)
CADAYS=3650
# Wie lange sollen die Server Zertifikate gültig sein? (In Tagen)
CERTDAYS=3650












































###############################################################################
###############################################################################
###############################################################################
# WEITERE SYSTEMEINSTELLUNGEN! Bitte NICHT Anpassen! :)
###############################################################################
# Automatische Variablen
HOSTNAME=`/usr/bin/uname -n`
DATE=`/bin/date +%Y%m%d%H%M%S`

# Welche Dienste sollen ein SSL-Zertifikat erhalten?
SSLSERVICES="apache cyrus sendmail webmin"

### Ordner
SSLCRTDIR=$INSTALLPATH/ssl/ssl.crt
SSLCSRDIR=$INSTALLPATH/ssl/ssl.csr
SSLKEYDIR=$INSTALLPATH/ssl/ssl.key
SSLALLDIR="$SSLCRTDIR $SSLCSRDIR $SSLKEYDIR"

# Programme
BINAWK=/usr/bin/awk
BINCAT=/bin/cat
BINCD=/usr/bin/cd
BINCHMOD=/bin/chmod
BINCHOWN=/usr/sbin/chown
BINCP=/bin/cp
BINECHO=/bin/echo
BINDATE=/bin/date
BINEGREP=/usr/bin/egrep
BINGREP=/usr/bin/grep
BINID=/usr/bin/id
BINKILLALL=/usr/bin/killall
BINMKDIR=/bin/mkdir
BINMV=/bin/mv
BINOPENSSL=/usr/bin/openssl
BINPKGADD=/usr/sbin/pkg_add
BINPKGINFO=/usr/sbin/pkg_info
BINPKGVERSION=/usr/sbin/pkg_version
BINPORTINSTALL=/usr/local/sbin/portinstall
BINPORTUPGRADE=/usr/local/sbin/portupgrade
BINPS=/bin/ps
BINPW=//usr/sbin/pw
BINRM=/bin/rm
BINSED=/usr/bin/sed
BINSLAPADD=/usr/local/sbin/slapadd
BINTEST=/bin/test
BINTOUCH=/usr/bin/touch
BINTR=/usr/bin/tr
BINWC=/usr/bin/wc

# Nachrichten
MSGEXISTBACKUP="Existiert bereits, wird zuerst gesichert."
MSGEXIST="Existiert bereits. OK!"
MSGCREATE="Existiert nicht, wird nun angelegt."
MSGCHECKAPPS="Installation der Programme überpruefen:"


$BINECHO "[$COMPANY] ################################################"
$BINECHO "[$COMPANY] ################################################" >> $INSTALLLOG
$BINECHO "[$COMPANY] # Systemcheck"
$BINECHO "[$COMPANY] # Systemcheck" >> $INSTALLLOG
$BINECHO "[$COMPANY] ################################################"
$BINECHO "[$COMPANY] ################################################" >> $INSTALLLOG

###############################################################################
# Backupverzeichnis anlegen
#
$BINECHO "[$COMPANY] [$BACKUPDIR]"
if [ -d $BACKUPDIR ]; then
	$BINECHO "[$COMPANY]  - $MSGEXISTBACKUP"
	$BINMV "$BACKUPDIR" "$BACKUPDIR$DATE"
fi

$BINECHO "[$COMPANY]  - $MSGCREATE"
$BINECHO "[$COMPANY]  - Erstelle $BACKUPDIR"
$BINMKDIR -p $BACKUPDIR/ssl
$BINCHMOD 700 $BACKUPDIR

###############################################################################
# Check, ob die Log-Datei vorhanden ist. Wenn nicht = Anlegen!
#
$BINECHO "[$COMPANY] [$INSTALLLOG]"
if [ -w $INSTALLLOG ]; then
	$BINECHO "[$COMPANY]  - $MSGEXISTBACKUP"
	$BINMV "$INSTALLLOG" "$BACKUPDIR/install.log$DATE"
	$BINECHO "[$COMPANY]  - Erstelle $INSTALLLOG"
else
	$BINECHO "[$COMPANY]  - $MSGCREATE"
	$BINECHO "[$COMPANY]  - Erstelle neue $INSTALLLOG"
fi
$BINTOUCH $INSTALLLOG
$BINCHMOD 700 $INSTALLLOG


$BINECHO "[$COMPANY] ################################################"
$BINECHO "[$COMPANY] ################################################" >> $INSTALLLOG
$BINECHO "[$COMPANY] # Erstellung der SSL-Zertifikate"
$BINECHO "[$COMPANY] # Erstellung der SSL-Zertifikate" >> $INSTALLLOG
$BINECHO "[$COMPANY] ################################################"
$BINECHO "[$COMPANY] ################################################" >> $INSTALLLOG


###############################################################################
# SSL Verzeichnisse anlegen
#
$BINECHO "[$COMPANY] Zielverzeichnisse werden geprüft ... "
$BINECHO "[$COMPANY] Zielverzeichnisse werden geprüft ... " >> $INSTALLLOG
for i in $SSLALLDIR; do
	if [ -d $i ]; then
		$BINECHO "[$COMPANY]   $i $MSGEXISTBACKUP"
		$BINECHO "[$COMPANY]   $i $MSGEXISTBACKUP" >> $INSTALLLOG
		$BINMV "$i" "$BACKUPDIR$DATE/ssl/"
	fi

	$BINECHO "[$COMPANY]   $i $MSGCREATE"
	$BINECHO "[$COMPANY]   $i $MSGCREATE" >> $INSTALLLOG
	$BINMKDIR -p $i
	$BINCHMOD 700 $i
	
done

$BINECHO "----------"
$BINECHO "----------" >> $INSTALLLOG


###############################################################################
#  find some random files
#  (do not use /dev/random here, because this device
#  doesn't work as expected on all platforms)
$BINECHO "[$COMPANY] Suchen einiger zufälliger Dateien ... "
$BINECHO "[$COMPANY] Suchen einiger zufälliger Dateien ... " >> $INSTALLLOG
randfiles=''
for file in /var/log/messages \
	/etc/hosts /etc/group /etc/resolv.conf /bin/ls; do
if [ -r $file ]; then
	if [ ".$randfiles" = . ]; then
		randfiles="$file"
	else
		randfiles="${randfiles}:$file"
	fi
fi
done

###############################################################################
#  Zufallsdateien finden
#
$BINECHO "[$COMPANY] Zufallsdateien initialisieren ... "
$BINECHO "[$COMPANY] Zufallsdateien initialisieren ... " >> $INSTALLLOG
if [ -f $HOME/.rnd ]; then
	RANDFILE="$HOME/.rnd"
else
	RANDFILE=".mkcert.rnd"
	(ps; date) >$RANDFILE
fi
export RANDFILE

$BINECHO "----------"
$BINECHO "----------" >> $INSTALLLOG


###############################################################################
# SCHRITT 1: Generiere privaten RSA Schluessel fuer CA (1024 bit)"
#
$BINECHO "[$COMPANY] SCHRITT 1: Generiere privaten RSA Schluessel fuer CA (1024 bit)"
$BINECHO "[$COMPANY] SCHRITT 1: Generiere privaten RSA Schluessel fuer CA (1024 bit)" >> $INSTALLLOG
$BINECHO "[$COMPANY]   $SSLKEYDIR/ca.key"
$BINECHO "[$COMPANY]   $SSLKEYDIR/ca.key" >> $INSTALLLOG
$BINECHO "[$COMPANY] "
$BINECHO "[$COMPANY] " >> $INSTALLLOG

$BINOPENSSL genrsa -rand $randfiles -out $SSLKEYDIR/ca.key 1024 2>> $INSTALLLOG


###############################################################################
# SCHRITT 2: Generiere X.509 Signierungsanforderungszertifikat fuer CA
#
$BINECHO "[$COMPANY] SCHRITT 2: Generiere X.509 Signierungsanforderungszertifikat fuer CA"
$BINECHO "[$COMPANY] SCHRITT 2: Generiere X.509 Signierungsanforderungszertifikat fuer CA" >> $INSTALLLOG
$BINECHO "[$COMPANY]   $SSLCSRDIR/ca.csr"
$BINECHO "[$COMPANY]   $SSLCSRDIR/ca.csr" >> $INSTALLLOG
$BINECHO " "
$BINECHO " " >> $INSTALLLOG

$BINCAT >.mkcert.cfg <<EOT
[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
[ req_DN ]
countryName                     = "1. Country Name             (2 letter code)"
countryName_default             = '$CACOMPANYCOUNTRY'
countryName_min                 = 2
countryName_max                 = 2
stateOrProvinceName             = "2. State or Province Name   (full name)    "
stateOrProvinceName_default     = '$CACOMPANYSTATE'
localityName                    = "3. Locality Name            (eg, city)     "
localityName_default            = '$CACOMPANYTOWN'
0.organizationName              = "4. Organization Name        (eg, company)  "
0.organizationName_default      = '$CACOMPANY'
organizationalUnitName          = "5. Organizational Unit Name (eg, section)  "
organizationalUnitName_default  = certificate authority
commonName                      = "6. Common Name              (eg, CA name)  "
commonName_max                  = 64
commonName_default              = '$CACOMPANY' CA
emailAddress                    = "7. Email Address            (eg, name@FQDN)"
emailAddress_max                = 255
emailAddress_default            = '$CACOMPANYEMAIL'
EOT

$BINOPENSSL req -config .mkcert.cfg -new -key $SSLKEYDIR/ca.key -out $SSLCSRDIR/ca.csr
$BINRM -f .mkcert.cfg

$BINECHO " "
$BINECHO " " >> $INSTALLLOG


###############################################################################
# SCHRITT 3: Generiere selbstsigniertes X.509 CA Zertifikat
#
$BINECHO "[$COMPANY] SCHRITT 3: Generiere selbstsigniertes X.509 CA Zertifikat"
$BINECHO "[$COMPANY] SCHRITT 3: Generiere selbstsigniertes X.509 CA Zertifikat" >> $INSTALLLOG
$BINECHO "[$COMPANY]   $SSLCRTDIR/ca.crt"
$BINECHO "[$COMPANY]   $SSLCRTDIR/ca.crt" >> $INSTALLLOG

$BINCAT >.mkcert.cfg <<EOT
extensions = x509v3
[ x509v3 ]
subjectAltName   = email:copy
basicConstraints = CA:true,pathlen:0
nsComment        = "$COMPANY generated CA certificate"
nsCertType       = sslCA
EOT
extfile="-extfile .mkcert.cfg"

$BINOPENSSL x509 $extfile -days $CADAYS -signkey $SSLKEYDIR/ca.key -in $SSLCSRDIR/ca.csr -req -out $SSLCRTDIR/ca.crt 2>> $INSTALLLOG
$BINRM -f .mkcert.cfg

$BINECHO "[$COMPANY]"
$BINECHO "[$COMPANY]" >> $INSTALLLOG
$BINECHO "[$COMPANY]   Verify: matching certificate & key modulus"
$BINECHO "[$COMPANY]   Verify: matching certificate & key modulus"  >> $INSTALLLOG
modcrt=`$BINOPENSSL x509 -noout -modulus -in $SSLCRTDIR/ca.crt | $BINSED -e 's;.*Modulus=;;'`
modkey=`$BINOPENSSL rsa -noout -modulus -in $SSLKEYDIR/ca.key | $BINSED -e 's;.*Modulus=;;'`
if [ ".$modcrt" != ".$modkey" ]; then
	$BINECHO "[$COMPANY]   [ERROR] Failed to verify modulus on resulting X.509 certificate" 1>&2
	$BINECHO "[$COMPANY]   [ERROR] Failed to verify modulus on resulting X.509 certificate" >> $INSTALLLOG
	exit 1
fi
$BINECHO "[$COMPANY]   Verify: matching certificate signature"
$BINECHO "[$COMPANY]   Verify: matching certificate signature" >> $INSTALLLOG
$BINOPENSSL verify $SSLCRTDIR/ca.crt >> /dev/null
if [ $? -ne 0 ]; then
	$BINECHO "[$COMPANY]   [ERROR] Failed to verify signature on resulting X.509 certificate" 1>&2
	$BINECHO "[$COMPANY]   [ERROR] Failed to verify signature on resulting X.509 certificate" >> $INSTALLLOG
	exit 1
fi

$BINECHO "[$COMPANY] "
$BINECHO "[$COMPANY] " >> $INSTALLLOG


###############################################################################
# SCHRITT 4: Generiere private Schluessel (1024 bit)
#
$BINECHO "[$COMPANY] SCHRITT 4: Generiere privaten Schluessel (1024 bit)"
$BINECHO "[$COMPANY] SCHRITT 4: Generiere private Schluessel (1024 bit)" >> $INSTALLLOG
for i in $SSLSERVICES; do
	$BINECHO "[$COMPANY]   Generiere private Schluessel fur $i (1024 bit)"
	$BINECHO "[$COMPANY]   Generiere private Schluessel fur $i (1024 bit)" >> $INSTALLLOG
	$BINECHO "[$COMPANY]   $SSLKEYDIR/$i.key"
	$BINECHO "[$COMPANY]   $SSLKEYDIR/$i.key" >> $INSTALLLOG
	$BINOPENSSL genrsa -rand $randfiles -out $SSLKEYDIR/$i.key 1024 2>> $INSTALLLOG
done

$BINECHO "[$COMPANY] "


###############################################################################
# SCHRITT 5: Generiere X.509 Zertifikatssignierungsanforderung
#
$BINECHO "[$COMPANY] SCHRITT 5: Generiere X.509 Zertifikatssignierungsanforderungen"
$BINECHO "[$COMPANY] SCHRITT 5: Generiere X.509 Zertifikatssignierungsanforderungen" >> $INSTALLLOG
for i in $SSLSERVICES; do
	$BINECHO "[$COMPANY]   Generiere X.509 Zertifikatssignierungsanforderungen fuer $i"
	$BINECHO "[$COMPANY]   Generiere X.509 Zertifikatssignierungsanforderungen fuer $i" >> $INSTALLLOG
	$BINECHO "[$COMPANY]   $SSLCSRDIR/$i.csr"
	$BINECHO "[$COMPANY]   $SSLCSRDIR/$i.csr" >> $INSTALLLOG
	$BINECHO " "
	$BINECHO " " >> $INSTALLLOG
	$BINCAT >.mkcert.cfg <<EOT
[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
[ req_DN ]
countryName                     = "1. Country Name             (2 letter code)"
countryName_default             = '$CERTCOMPANYCOUNTRY'
countryName_min                 = 2
countryName_max                 = 2
stateOrProvinceName             = "2. State or Province Name   (full name)    "
stateOrProvinceName_default     = '$CERTCOMPANYSTATE'
localityName                    = "3. Locality Name            (eg, city)     "
localityName_default            = '$CERTCOMPANYTOWN'
0.organizationName              = "4. Organization Name        (eg, company)  "
0.organizationName_default      = '$CERTCOMPANY'
organizationalUnitName          = "5. Organizational Unit Name (eg, section)  "
organizationalUnitName_default  = '$i'
commonName                      = "6. Common Name              (eg, FQDN)     "
commonName_max                  = 64
commonName_default              = '$HOSTNAME'
emailAddress                    = "7. Email Address            (eg, name@fqdn)"
emailAddress_max                = 255
emailAddress_default            = '$i'@'$HOSTNAME'
EOT

$BINOPENSSL req -config .mkcert.cfg -new -key $SSLKEYDIR/$i.key -out $SSLCSRDIR/$i.csr
$BINRM -f .mkcert.cfg
$BINECHO " "
done



###############################################################################
# SCHRITT 6: Generiere von CA signierte X.509 Zertifikate
#
$BINECHO "[$COMPANY]   SCHRITT 6: Generiere von CA signierte X.509 Zertifikate" 
$BINECHO "[$COMPANY]   SCHRITT 6: Generiere von CA signierte X.509 Zertifikate" >> $INSTALLLOG
for i in $SSLSERVICES; do
	$BINECHO "[$COMPANY]   Signiere X.509 Zertifikat fuer $i"
	$BINECHO "[$COMPANY]   Signiere X.509 Zertifikat fuer $i" >> $INSTALLLOG
	$BINECHO "[$COMPANY]   $SSLCRTDIR/$i.crt"
	$BINECHO "[$COMPANY]   $SSLCRTDIR/$i.crt" >> $INSTALLLOG
	$BINECHO " "
	$BINCAT >.mkcert.cfg <<EOT
extensions = x509v3
[ x509v3 ]
subjectAltName   = email:copy
nsComment        = "$COMPANY generated $i certificate"
nsCertType       = server
EOT

if [ ! -f .mkcert.serial ]; then
	$BINECHO '01' >.mkcert.serial
fi
$BINOPENSSL x509 $extfile -days $CERTDAYS -CAserial .mkcert.serial -CA $SSLCRTDIR/ca.crt -CAkey $SSLKEYDIR/ca.key -in $SSLCSRDIR/$i.csr -req -out $SSLCRTDIR/$i.crt 2>> $INSTALLLOG

$BINRM -f .mkcert.cfg

$BINECHO "[$COMPANY]   Verify: matching certificate & key modulus"
modcrt=`$BINOPENSSL x509 -noout -modulus -in $SSLCRTDIR/$i.crt | $BINSED -e 's;.*Modulus=;;'`
modkey=`$BINOPENSSL rsa -noout -modulus -in $SSLKEYDIR/$i.key | $BINSED -e 's;.*Modulus=;;'`
if [ ".$modcrt" != ".$modkey" ]; then
	$BINECHO "[$COMPANY]   mkcert.sh:Error: Failed to verify modulus on resulting X.509 certificate" 1>&2
	exit 1
fi

$BINECHO "[$COMPANY]   Verify: matching certificate signature"
$BINOPENSSL verify -CAfile $SSLCRTDIR/ca.crt $SSLCRTDIR/$i.crt
if [ $? -ne 0 ]; then
	$BINECHO "[$COMPANY]   mkcert.sh:Error: Failed to verify signature on resulting X.509 certificate" 1>&2
	exit 1
fi
$BINECHO " "
done


###############################################################################
# STEP 7: Enrypting $algo private key of CA with a pass phrase for security
#

while [ 1 ]; do
$BINECHO dummy | $BINAWK '{ printf("Privaten CA Schluessel mit Passwort absichern? [J/n]: "); }'
read rc
if [ ".$rc" = .n -o  ".$rc" = .N ]; then
	rc="n"
	break
fi
if [ ".$rc" = .j -o  ".$rc" = .J -o ".$rc" = . ]; then
	rc="y"
	break
fi
done

if [ ".$rc" = .y ]; 
then
	$BINOPENSSL rsa -des3 -in  $SSLKEYDIR/ca.key -out $SSLKEYDIR/ca.key.crypt
	if [ $? -ne 0 ]; then
		$BINECHO "[$COMPANY]   mkcert.sh:Error: Failed to encrypt $algo private key" 1>&2
		exit 1
	fi
	(umask 077; $BINCP $SSLKEYDIR/ca.key.crypt $SSLKEYDIR/ca.key)
	$BINRM -f $SSLKEYDIR/ca.key.crypt
	$BINECHO "[$COMPANY]   Sehr gut! Sie benutzen einen gesicherten privaten Schluessel!"
	$BINECHO "[$COMPANY]   Sehr gut! Sie benutzen einen gesicherten privaten Schluessel!" >> $INSTALLLOG
else
	$BINECHO "[$COMPANY]   Achtung! Der private CA Schluessel ist NICHT abgesichert!"
	$BINECHO "[$COMPANY]   Achtung! Der private CA Schluessel ist NICHT abgesichert!" >> $INSTALLLOG
fi

rm -r $SSLCSRDIR

###############################################################################
# Fertig
#
$BINECHO " "
$BINECHO " " >> $INSTALLLOG
$BINECHO "[$COMPANY] Zertifikate erstellt!"
$BINECHO "[$COMPANY] Zertifikate erstellt!" >> $INSTALLLOG

