#!/bin/bash

RED='\033[31m' # Красный
GREEN='\033[32m' # Зелёный
NOCOLOR='\033[0m' # Без цвета

function showHelp() {
	HELP_MESSAGE="
Скрипт создания и установки сертификатов Крипто-Про Linux. EOSSOFT 2024.
Использование скрипта. [ОПЦИИ]

ОПЦИИ:

-c, --container CONTAINER
    Указать контейнер ключей. Если указать несуществующий, то скрипт попытается его создать По умолчанию сгенерирует случайный.

-s, --store STORE
    Указать хранилище (sscu или sslm). По умолчанию \"sscu\".

-e, --enumreader ENUMREADER
    Указать ENUMREADER. По умолчанию \"HDIMAGE\".

-p, --path PATH_CERT
    Указать путь к файлу сертификата *.p7b, чтобы установить его. Необязательный. Если не указать этот параметр, то будет сделан запрос к cryptopro.ru чтобы получить новый сертификат.

-dn, --distname DN
    Указать Distinguished Name. По умолчанию \"INN=007814508921, E=user@site.ru, C=RU, CN=Иванов Иван Иванович, SN=Иванов\".

-rFN, --req-file-name REQ_FILE_NAME
    Указать имя файла запроса. По умолчанию \"request.req\".

-cFN, --cert-file-name CERT_FILE_NAME
    Указать имя файла сертификата. По умолчанию \"certnew.p7b\".

-or, --only-request
    Сгенирировать только файл запроса *.req . Это флаг, аргументы не требуются. Не будет запрашивать *.p7b цепочку с cryptopro.ru. По умолчанию выключено.

-h, --help
    Показать это справочное сообщение и выйти."

	echo "$HELP_MESSAGE"
	exit 1
}

while (( "$#" )); do
	case "$1" in
		-c|--container)
			CONTAINER=$2
			shift 2
			;;
		-s|--store)
			STORE=$2
			shift 2
			;;
		-e|--enumreader)
			ENUMREADER=$2
			shift 2
			;;
		-p|--path) #Path to the *.p7b certificate file
			PATH_CERT=$2
			shift 2
			;;
		-dn|--distname) #Distinguished Name
			DN=$2
			shift 2
			;;
		-rFN|--req-file-name)
			REQ_FILE_NAME=$2
			shift 2
			;;
		-cFN|--cert-file-name)
			CERT_FILE_NAME=$2
			shift 2
			;;
		-or|--only-request) #flag. Create a request only
			ONLY_REQUEST="YES"
			shift
			;;
		-h|--help)
			showHelp
			exit 1
			;;
		--)
			shift
			break
			;;
		*)
			echo "Ошибка. Недопустимый ключ $1"
			exit 1
	esac
done

function startScript() {
	checkOS
	checkArchitecture
	echo "The path to CryptoPRO: ${FOLDER_BIN_CP}"
	
	validationOfEnteredValues
	
	if [[ ${PATH_CERT} == '' ]]; then
		genRequest
		if [[ ${ONLY_REQUEST} != 'YES' ]]; then
			getFileP7B
		fi
	fi

	installCert
	exit 1
}

function validationOfEnteredValues() {
	if [[ ${PATH_CERT} != '' ]]; then
		if [[ ! -e ${PATH_CERT} ]]; then
			echo "File ${PATH_CERT} does not exist"
			exit 1
		else
			echo "PATH_CERT=\"$PATH_CERT\""
		fi
	fi

	if [[ ${STORE} == 'sscu' || ${STORE} == '' ]]; then
		STORE="uMy";
		echo "STORE=\"$STORE\" (sscu)"
	fi

	if [[ ${STORE} == 'sslm' ]]; then
		STORE="mMy";
		echo "STORE=\"$STORE\" (sslm)"
	fi

	if [[ ${STORE} != 'uMy' && ${STORE} != 'mMy' ]]; then
		echo "Store \"${STORE}\" is incorrect"
		exit 1
	fi

	if [[ ${DN} == '' ]]; then
		DN="INN=007814508921, E=user@site.ru, C=RU, CN=Иванов Иван Иванович, SN=Иванов";
	fi
	if [[ ${PATH_CERT} == '' ]]; then
		echo "DN=\"$DN\""
	fi

	if [[ ${ENUMREADER} == '' ]]; then
		ENUMREADER="HDIMAGE";
	fi

	checkEnumreaders

	if [[ ${CONTAINER} != '' ]]; then
		FULL_PATH_CONTAINER=\\\\.\\${ENUMREADER}\\${CONTAINER}
	else
		RANDOM_CONTAINER=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 10)
		echo -e "Container was not specified. Randomly generated container name: $RANDOM_CONTAINER"
		FULL_PATH_CONTAINER="\\\\.\\${ENUMREADER}\\${RANDOM_CONTAINER}"
		CONTAINER=${RANDOM_CONTAINER}
	fi

	echo "FULL_PATH_CONTAINER=\"$FULL_PATH_CONTAINER\""
	checkCountainer

	if [[ ${REQ_FILE_NAME} == '' ]]; then
		REQ_FILE_NAME="request.req";
	fi
	echo "REQ_FILE_NAME \"${REQ_FILE_NAME}\""
	if [[ ${CERT_FILE_NAME} == '' ]]; then
		CERT_FILE_NAME="certnew.p7b";
	fi
	echo "CERT_FILE_NAME \"${CERT_FILE_NAME}\""
}

function checkOS() {
	if [[ -e /etc/os-release ]]; then
		source /etc/os-release
		OS="${ID}"
		VERSION_OS="${VERSION}"
	else
		echo -e "${RED}Your OS Linux is not supported${NOCOLOR}"
		exit 1
	fi
}

function checkArchitecture() {
	UNAME_RESULT=$(uname -m)
	
	if [[ ${UNAME_RESULT} == 'x86_64' ]]; then
		FOLDER_BIN_CP="/opt/cprocsp/bin/amd64/"
		FOLDER_SBIN_CP="/opt/cprocsp/sbin/amd64/"
	fi

	if [[ ${UNAME_RESULT} == 'e2k' ]]; then
		FOLDER_BIN_CP="/opt/cprocsp/bin/e2k64/"
		FOLDER_SBIN_CP="/opt/cprocsp/sbin/e2k64/"
	fi

	if [[ ! -e ${FOLDER_BIN_CP} ]]; then
		echo -e "${RED}CryptoPro folder not found or your architecture does not support${NOCOLOR}"
		exit 1
	fi
}

function checkEnumreaders() {
	strEnumReaders=$(${FOLDER_SBIN_CP}cpconfig -hardware reader -view | grep 'Nick name:' | sed 's/Nick name: //g')
	arrEnumReaders=(${strEnumReaders//$'\n'/ })

	if [[ "${arrEnumReaders[@]}" =~ "${ENUMREADER}" ]]; then
    	echo "EnumeReader \"${ENUMREADER}\" exists"
    else
    	echo "EnumeReader \"${ENUMREADER}\" does not exists"
    	${FOLDER_SBIN_CP}cpconfig -hardware reader -add ${ENUMREADER} store

    	if [[ $? != 0 ]]; then
			exit 1
		fi
		echo -e "${GREEN}EnumeReader \"${ENUMREADER}\" был успешно создан${NOCOLOR}"
	fi
}

function checkCountainer() {
	strCounts=$(${FOLDER_BIN_CP}csptest -keyset -enum_cont -fqcn -verifyc | iconv -f cp1251 | grep "${ENUMREADER}")
	arrCounts=(${strCounts//$'\n'/ })

	if [[ "${arrCounts[@]}" =~ "${FULL_PATH_CONTAINER}" ]]; then
    	echo "Countainer \"${CONTAINER}\" exists"
    else
    	echo "Countainer \"${CONTAINER}\" does exists"
    	${FOLDER_BIN_CP}csptest -keyset -newkeyset -cont "${FULL_PATH_CONTAINER}"

    	if [[ $? != 0 ]]; then
			exit 1
		fi
		echo -e "${GREEN}Контейнер \"${CONTAINER}\" был успешно создан${NOCOLOR}"
	fi
}

function genRequest() {
	OUTPUT_REQUEST=$(${FOLDER_BIN_CP}cryptcp -creatrqst -dn "${DN}" -nokeygen -both -ku -cont "${CONTAINER}" "${REQ_FILE_NAME}" 2>&1)

	if [ $? -eq 0 ]
	then
		echo -e "${GREEN}Файл запроса \"$REQ_FILE_NAME\" успешно сгенирирован!${NOCOLOR}"

	    echo $OUTPUT_REQUEST
	    REQ=$(cat "$REQ_FILE_NAME")
	    echo $REQ

	    REQ_URLENCODING=$(echo "${REQ}" | sed ':a;N;$!ba;s/\n/%0D%0A/g' | sed 's/\//%2F/g' | sed 's/+/%2B/g' | sed 's/ /+/g')
	else
	    echo -e "${RED}Ошибка при формировании файла запроса \"$REQ_FILE_NAME\"${NOCOLOR}"
	    echo $OUTPUT_REQUEST
	    exit 1
	fi
}

function getFileP7B() {
	REQ_ID=$(curl -X POST -d "Mode=newreq&CertRequest=\"${REQ_URLENCODING}\"&SaveCert=yes" https://www.cryptopro.ru/certsrv/certfnsh.asp | grep -oP 'certnew.p7b\?ReqID=\K[^&]*')
	if [[ ${REQ_ID} == '' ]]; then
		${REQ_ID}>responseError.txt
		echo -e "${RED}Ошибка! ReqID не найден в ответе. Ошибка запроса к https://www.cryptopro.ru/certsrv/certfnsh.asp${NOCOLOR}"
		exit 1
	fi
	echo "ReqID=$REQ_ID"
	curl -o ${CERT_FILE_NAME} "https://www.cryptopro.ru/certsrv/certnew.p7b?ReqID=${REQ_ID}&Enc=bin"

	PATH_CERT=${CERT_FILE_NAME}
}

function installCert() {
	echo -e "${RED}Внимание! Сейчас вам нужно будет выбрать сертификат с Subject=\"${DN}\". Нажмите любую клавишу для продолжения...${NOCOLOR}"
	read -n 1

	${FOLDER_BIN_CP}certmgr -install -store "${STORE}" -file "${PATH_CERT}" -container "${FULL_PATH_CONTAINER}"

	if [ $? -eq 0 ]
	then
	    printf "${GREEN}Сертификат был успешно установлен в ${FULL_PATH_CONTAINER}, ${STORE}!${NOCOLOR}\\n"

	    echo -e "${RED}Внимание! Сейчас вам нужно будет выбрать КОРНЕВОЙ сертификат (не наш). Нажмите любую клавишу для продолжения...${NOCOLOR}"
		read -n 1
	    
	    ${FOLDER_BIN_CP}certmgr -install -store uRoot -file "${PATH_CERT}"
	    if [ $? -eq 0 ]
		then
		    printf "${GREEN}Корневой сертификат был успешно установлен в ${FULL_PATH_CONTAINER}, ${STORE}!${NOCOLOR}\\n"

		else
		    echo -e "${RED}Ошибка при добавлении корневого сертификата${NOCOLOR}"
		fi
	else
	    echo -e "${RED}Ошибка при добавлении сертификата${NOCOLOR}"
	fi
}

startScript
