#!/bin/bash

#-------------------------------------------------------------------
# Este é um script bash desenvolvido para obter os certificados dos 
# servidores das unidades autorizadoras para NFe, NFCe, MDFe e CTe
# ouseja basicamente dos serviços do projeto SPED
# Os certificados das autorizadoras são armazenados nos arquivos
#
# cacerts.crt -- no formato PEM para uso no Linux e PHP
# Cacert       -- no formato Java Keystore para uso do Java  
# 
# NOTA: Os certificados dos servidores tem validade e portanto 
#       este script deve ser usado regularmente para manter os 
#       certificados válidos disponíveis para uso de forma a 
#       evitar negativas de acesso devido a regras de segurança
#       estabelecidas
#
# Exemplo de uso :
#
# userprompt$ ./makeCA sped_cacerts.pem SpedCacert autorizadores.list
#
# Em SO Linix (Debian Like) os certificados podem ser colocados em 
# /usr/share/ca-certificates e instalados com o comando update-ca-certificates.
# Para os browsers, em ambiente Linux, pode ser usado o comando
# certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n <certificate nickname> -i <certificate filename>
#
# Author: Roberto L. Machado <linux dot rlm at gmail dot com>
# Version: 0.3 de 2017-05-03
# Copyright (c) 2016 Roberto L. Machado
# Lisence: LGPLv3, GPLv3 or MIT
#-------------------------------------------------------------------


PORT=443
KEYSTOREFILE=$2
KEYSTOREPASS=changeit
CERTFILE=$1
SEFAZ=$3
FAIL=""
PREFIX=${KEYSTOREFILE:0:3}
LOGFILE=$PREFIX"_fail.log"

#--------------------------------------------------------------
# Esta função lê cada linha do arquivo que contêm
# as URLs das autorizadoras e executa a tarefa de baixar 
# os certificados, agregar-los para uso de sistemas 
# PHP no arquivo nfe_cacerts.crt
# e ainda monta um keystore JAVA com esses mesmos certificados
# no arquivo NFeCacerts
#--------------------------------------------------------------
function readURLs()
{
    while read url
    do 
       echo -e "$url"
       getSSLCert $url
       groupCerts $url
       addCertsKeyStore $url
       cleanCert $url
    done < $1
}

#-------------------------------------------------------------------------
# Esta função acessa a URL e recupera TODOS os certificados do servidor
#-------------------------------------------------------------------------
function getSSLCert()
{
    # remove o certificado anterior, se houver
    rm -f $1.cert
    # busca os dados SSL na URL, listando todos os certificados da cadeia e separa os certificados das demais informações 
    timeout 4 openssl s_client -showcerts -prexit -connect $1:$PORT < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > $1.crt
    # verifique se o arquivo não está vazio, isso ocorre caso o certificado não seja fornecido pela URL
    # é necessário investigar esses casos pois pode estar fora do ar temporariamente ou o servidor tem falhas em 
    # sua configuração impedindo a recuperação do certificado nesse caso a importação deverá ser feita manualmente  
    if [ -s "$1.crt" ]
    then
        # deixe o arquivo ficar
        echo "SUCESSO $1" >> $LOGFILE
    else
        if [ -z "$1" ]
        then
            echo ""
        else
            FAIL+="FALHA $1\n"
            echo "FALHA $1" >> $LOGFILE
            echo "##########################################################################" 
            echo "# Não foi possivel pegar o certificado de $1"
            echo "##########################################################################"
            rm -f $1.crt
        fi    
    fi
}

#-----------------------------------------------------
# Esta função agrega os certificados em formato PEM
# para usos em sistemas Linux e PHP
#-----------------------------------------------------
function groupCerts()
{
    if [ -f $1.crt ]
    then
        cat $1.crt >> $CERTFILE
    fi    
}

#-----------------------------------------
# Esta função adiciona os certificados a 
# um KeyStore Java 
#-----------------------------------------
function addCertsKeyStore()
{
    if [ -f $1.crt ]
    then
        # conta quantos certificados estão contidos no arquivo
        N=$(grep 'END CERTIFICATE' $1.crt | wc -l)
        # split cada certificado em um arquivo diferente
        awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert." c ".pem"}' < $1.crt
        for i in `seq 1 $N`;
        do
            d=$(($i-1))
            # carrega o certificado no keystore
            keytool -import -noprompt -trustcacerts -alias "$1-"$d -file "cert.$i.pem" -keystore $KEYSTOREFILE -storepass $KEYSTOREPASS
        done
        # remove qualquer arquivo cert.?.pem
        rm -f cert.*.pem
    fi	
}

#-------------------------------------
# Esta função remove os arquivos 
# para efeito de limpeza do diretorio
#-------------------------------------
function cleanCert()
{
    if [ -f $1.crt ]
    then
        echo $1
        rm -f $1.crt
    fi  
}

#-----------------------------------------------
# Esta função mostra a forma de uso do script
#-----------------------------------------------
function displayUsage()
{
    echo ""
    echo "Este script monta os certificados dos autorizadores do sistema SPED"
    echo "o OpenSSL e o Java devem estar instalados e corretamente configurados no ambiente"
    echo "e requer 3 (tres) parametros para funcionar"
    echo -e "\nUsage:\n$0 [cacert file] [keystore file] [url list file]\n"
    echo -e "   [cacert file]   <nome do arquivo cacert>"
    echo -e "   [keystore file] <nome do arquivo keystore>"
    echo -e "   [url list file] <nome do arquivo com a lista de urls>\n"
    echo -e " Exemplo: ./makeCA cacerts.crt Cacert autorizadores.list\n"
}

# se menos de 3 algumentos foram passados
if [  $# -le 2 ] 
then 
    displayUsage
    exit 1
fi 
 
# verifica se foi passado um -h ou --help
if [[ ( $# == "--help") ||  $# == "-h" ]] 
then 
    displayUsage
    exit 0
fi 

# verifica se a lista de url foi passada
if [ -f $SEFAZ ]
then
    echo ""
else
    echo -e "\nO arquivo com a lista de servidores não foi localizada.\n"
    exit 1
fi

# remove os arquivos anteriores
rm -f $CERTFILE
rm -f $KEYSTOREFILE
rm -f $LOGFILE
rm -f cert.*.pem

cp $JAVA_HOME/jre/lib/security/cacerts $KEYSTOREFILE

# executa a carga
readURLs $SEFAZ

# verifica quantos certificados foram importados
if [ -f $CERTFILE ]
then
    NUM=$(grep 'END CERTIFICATE' $CERTFILE | wc -l)
    echo -e "\nForam inclusos $NUM certificados ao keystore $KEYSTOREFILE e ao arquivo nfe_cacerts.crt\n"
else
    echo -e "\nNÃO FORAM INCLUSOS CERTIFICADOS !!!"
fi
    
# verifica se existe uma keystore
if [ -f $KEYSTOREFILE ]
then
    echo -e "Voce pode verificar pelos dados abaixo:\n\n"
    keytool -list -keystore ${KEYSTOREFILE} -storepass ${KEYSTOREPASS}
fi

# verifica se a variavel FAIL contem algo
if [ -z "$FAIL" ]
then
    echo ""
else
    echo -e "Os seguintes servidores não forneceram seus certificados:\n"
    echo -e $FAIL
fi

# sai    
exit 0
