#!/bin/sh

# File under Perl Artistic Licence 2.0
# http://www.opensource.org/licenses/artistic-license-2.0.php

# Copyright holder: TBS INTERNET SAS, France
# Author: JP Donnio
# Author : PALLAVIDINO Luc
# Contact: tag-nss-update-crl@tbs-internet.com
# http://www.tbs-certificats.com/
#
# Doc at: http://www.tbs-certificats.com/ssl/nss_tools_crl_ca_control.html
#---------------------------------------------------------------------
# Version: 1.6
# Date: 2009-08-24
#---------------------------------------------------------------------
# Version: 1.5
# Date: 2009-07-23
#---------------------------------------------------------------------
# Version: 1.4
# Date: 2009-05-15
#---------------------------------------------------------------------
# Version: 1.3
# Date: 2009-05-13
#---------------------------------------------------------------------
# Version: 1.2
# Date: 2009-05-05
#---------------------------------------------------------------------
# Version: 1.1
# Date: 2009-03-06
#---------------------------------------------------------------------
# Version: 1.0
# Date: 2008-08-20

# This program loads a list of CRLs into NSS (Firefox, Thunderbird, SeaMonkey, etc.)
#
# The file containing a list of CRL URLs is provided AS IS and does not 
# contains all the CRLs your need! Our list is cut-down because we have 
# also cut-down the approved CA list.
# Please review the list of CAs you have approved and make sure you have 
# all the CRLs. If you have left all the default firefox (NSS) builtin 
# roots (either ignorant or crazy), the provided file is FAR from complete!
#
# you may use something like
# certutil -L -h "Builtin Object Token" -d <your dir>
# to see all the roots. Look for the C and T flags!

# USAGE: nss_update_crl <cert8.db directory location> <update crl policy file> [nocache]

# Recuepration de l'emplacement DBDIR
if [ -d "$1" ]; then
	DBDIR=$1
else
	echo "Your DBDIR does not exist: $1"
	exit 1
fi

# Recuperation de l'emplacement de la liste des CRLs
if [ -e "$2" ]; then
	CRLLIST=$2 
fi

NOCACHE=""
# Recuperation de l'attribut "nocache" (pour curl) si il existe
if [ "$3" = "nocache" ] ; then
     NOCACHE="no-cache"
fi

# -B is needed to be able to import CRLs of intermediate certs not stored in the DB
# otherwise you get:
# crlutil: unable to import CRL: Peer's Certificate issuer is not recognized.
CRLPARAM="-B"

if [ ! -f "$CRLLIST" ]; then
        echo "Your CRLLIST file does not exist: $CRLLIST"
        exit 2
fi

if [ ! -s "$CRLLIST" ]; then
        echo "Your CRLLIST file is empty: $CRLLIST"
        exit 3
fi

# or set this by hand
CURL=$(which curl)
if [ ! -x "$CURL" ] ; then
	echo "Could not find curl, please edit script"
	echo http://curl.haxx.se/
	exit 5
fi

# or set this by hand
CRLUTIL=$(which crlutil)
if [ ! -x "$CRLUTIL" ] ; then
        echo "Could not find crlutil, please edit script"
	echo http://www.mozilla.org/projects/security/pki/nss/tools/crlutil.html
        exit 6
fi

# or set this by hand
CERTUTIL=$(which certutil)
if [ ! -x "$CERTUTIL" ] ; then
        echo "Could not find certutil, please edit script"
	echo http://www.mozilla.org/projects/security/pki/nss/tools/certutil.html
        exit 6
fi


RAND=$(dd if=/dev/urandom count=1 2>&1 | tail -n 1 | md5sum | cut -c 1-10);
if [ -d "$HOME/tmp/" ]; then
	TEMPDIR="$HOME/tmp/"
	TEMPFILE="$HOME/tmp/nss_update_crl.tmp.$RAND"
elif [ -d "/var/tmp/" ]; then
	TEMPDIR="/var/tmp/"
	TEMPFILE="/var/tmp/nss_update_crl.tmp.$RAND"
elif [ -d "/tmp/" ]; then
	TEMPDIR="/tmp/"
	TEMPFILE="/tmp/nss_update_crl.tmp.$RAND"
else
	echo "Could not locate a proper temporary directory"
	exit 4
fi

OIFS=$IFS
IFS=$'\n'

# On verifie si il faut vérifier la validité des certificats dans la base NSS
CERTTOCHECK=("")
if [ -e "$DBDIR/nss_verification_certificate.list" ] ; then
          i="0"
          # On ne garde que les certificats de la liste qui sont contenus dans la base NSS
          for CERT in $(egrep -v "^\s*#|^\s*$" "$DBDIR/nss_verification_certificate.list")
          do
	if [ "$("$CERTUTIL" -L -d "$DBDIR" | grep "$CERT")" ] ; then	          
	          # Si le certificat est contenu dans la base, on vérifie qu'il est actuellement valide, sinon on ne réalise pas les traitements
	          if [ "$("$CERTUTIL" -L -d "$DBDIR" -n "$CERT" 2>&1 | grep "bad database")" ] ; then
		# On met un # devant le libellé de l'erreur pour indiquer que l'on va renvoyer cette erreur sur la sortie std dans nss_root_util
		echo "#Failed : $CERT invalid, I can't perform restrictions on CA in ths NSS database ( $DBDIR )"
		exit 5
	          fi
	          # On enregistre la référence du certificat dans le tableau des certificats à traiter
	          CERTTOCHECK[$i]="$CERT"
	          i=$(($i + 1))
	fi
          done
          # On enregistre le chemin de la base de donnée de sauvegarde
          TEMPDB="$TEMPDIR/cert8.db.$RAND"
fi

# Get owner dbdir id
uid=$(stat --printf=%u "$DBDIR")
# Get group dbdir id
gid=$(stat --printf=%g "$DBDIR")

# experience shows that a backup is sometime useful!
BAKDIR="$DBDIR/cert8backup"
[ -d "$BAKDIR" ] || mkdir "$BAKDIR"

BAKFILE="$BAKDIR/cert8.db-$(date +%Y%m%d%H)"
[ -f "$BAKFILE" ] || cp -a "$DBDIR/cert8.db" "$BAKFILE"

error=0
for URLCRL in $(grep -v ^# "$CRLLIST")
do
               # Si l'on doit vérifier la validité des certificats dans la base NSS on réalise une copie de la base actuelle
	if [ "$TEMPDB" ] ; then
		cp "$DBDIR/cert8.db" "$TEMPDB"
	fi
	# On telecharge la nouvelle CRL
	$CURL -H "Pragma: $NOCACHE" -s "$URLCRL" -o "$TEMPFILE"
	if [ -f "$TEMPFILE" ] && [ -s "$TEMPFILE" ] ; then
		if ! $CRLUTIL -I $CRLPARAM -i "$TEMPFILE" -u "$URLCRL" -d "$TEMPDIR"  2>&1
		then
			error=$(($error + 1))
			echo "Error on $URLCRL for $DBDIR"
		fi
		# On verifie la validité des certificats dans la base NSS (si besoins est !!!)
		if [ "$TEMPDB" ] ; then
			# On parcours la liste des certificats à vérifier
			for CERT in "${CERTTOCHECK[@]}" 
			do
                                                       # Si le certificat contenu dans la base NSS est invalide on passe à la version antérieure de la base 
			          if [ "$("$CERTUTIL" -L -d "$DBDIR" -n "$CERT" 2>&1 | grep "bad database")" ] ; then
				# On met un # devant le libellé de l'erreur pour indiquer que l'on va renvoyer cette erreur sur la sortie std dans nss_root_util
				echo "#Failed : $CERT invalid, go back to the previous database version ( $DBDIR )";
				# On revient à la version précédente de la base
				cp "$TEMPDB" "$DBDIR/cert8.db"
				error=$(($error + 1))
			          fi   
			done
		fi
	fi
	[ -f "$TEMPFILE" ] && rm -f "$TEMPFILE"
	[ -e "$TEMPDB" ]  && rm -f "$TEMPDB"
done

#change file owner and group
if [ -e "$BAKDIR" ] ; then
     chown -R "$uid":"$gid" "$BAKDIR"
fi
#change file owner and group
if [ -e "$DBDIR/cert8.dir" ] ; then
     chown -R "$uid":"$gid" "$DBDIR/cert8.dir"
fi

if [ "$error" -eq "0" ] ; then
     echo "Update CRLs for $DBDIR : OK !"
fi
  
IFS=$OIFS
