Содержание
Набор скриптов для подписания и проверки ЭЦП КриптоПро на Linux
По соображениям безопасности:
- рекомендуется вынести взаимодействие с ЭЦП на отдельный сервер
- на сервере ЭЦП завести отдельного пользователя
- подключаться к серверу по ssh по ключу
Получение информации об установленных сертификатах
- certdigest.sh
#!/usr/bin/env bash # Получение информации об установленных сертификатах function digest() { echo '-------BEGIN CERTMGR-------' certmgr -list echo RESULT: $? echo '-------END CERTMGR-------' } digest
На выходе получаем текст, предназначенный для парсинга приложением. Для удобства отдельные секции отделены
--BEGIN--
и --END--
. Если скрипт создает файл, то путь к нему пишется в FILE
, и приложение должно самостоятельно его получить (например, используя scp
) и удалить.
Проверка подписей файла ЭЦП + Хеш MD5
На STDIN подается файл, первый параметр - команда check
- проверка подписи ЭЦП + хеш md5, md5
- только вычисление md5 суммы от оригинального файла (можно передать как подписанный, так и не подписанный - результат будет одинаков)
- check.sh
#!/usr/bin/env bash # Проверка подписей файла ЭЦП + Хеш MD5 # Вход: файл на STDIN, ... # Выход: результаты выполнения предназначены для парсинга SRC_FILE=`mktemp` ORIGIN_FILE=`mktemp` COMMAND=$1 cat - > $SRC_FILE # Получаем список сертификатов function certmgr_list() { CERTMGR_RESP=`certmgr -list -f "$SRC_FILE"` CERTMGR_CODE=$? if [ "$CERTMGR_CODE" -eq "0" ]; then SHAS=`echo "$CERTMGR_RESP" | grep "SHA1 Hash" | cut -f 2 -d "x"` fi } # Получаем данные сертификатов function certmgr_review() { echo --------- CERTIFICATE SECTION BEGIN --------- for SHA in $SHAS do CERT_FILE=`mktemp` cryptcp -nochain -copycert -thumbprint "$SHA" -f "$SRC_FILE" -df "$CERT_FILE" -der echo --------- CERTIFICATE BEGIN --------- echo CERTIFICATE SHA1: "$SHA" openssl x509 -in "$CERT_FILE" -inform der -text -noout -nameopt oneline,-esc_msb,-space_eq,sep_comma_plus echo --------- CERTIFICATE END --------- rm "$CERT_FILE" done echo --------- CERTIFICATE SECTION END --------- } # Отчет function summary() { echo --------- SUMMARY BEGIN --------- echo CERTMGR CODE: $CERTMGR_CODE echo CRYPTCP CODE: $CRYPTCP_CODE echo MD5SUM: $MD5 echo --------- SUMMARY END --------- } # Хеш файла в контейнере function md5_check_origin() { if [ -f "$ORIGIN_FILE" ]; then MD5=`md5sum "$ORIGIN_FILE" | cut -f 1 -d " "` # файл есть, вычисляем md5 оригинального файла else MD5='0' # ошибка проверки fi } # Хеш переданного файла function md5_check_src() { MD5=`md5sum "$SRC_FILE" | cut -f 1 -d " "` } # Проверка подписей function cryptcp_check() { echo --------- CRYPTCP BEGIN --------- case "$COMMAND" in "check" ) # Проверка подписи timeout 5s echo 'NNNNNNNNNNNNNNNNNNNN' | cryptcp -verify -nochain -norev -f "$SRC_FILE" "$SRC_FILE" "$ORIGIN_FILE" ;; "md5" ) # Только вычисление md5 timeout 5s echo 'NNNNNNNNNNNNNNNNNNNN' | cryptcp -verify -nochain -norev -f "$SRC_FILE" "$SRC_FILE" "$ORIGIN_FILE" ;; * ) echo 'No such command' exit 1 ;; esac CRYPTCP_CODE=$? echo --------- CRYPTCP END --------- } # *************** RUN **************** certmgr_list if [ "$CERTMGR_CODE" -eq "0" ]; then certmgr_review cryptcp_check md5_check_origin else md5_check_src fi summary rm "$SRC_FILE" rm "$ORIGIN_FILE"
Подписание файла ЭЦП
Используются хитрые приемы:
timeout 10s
не дает скрипту повиснуть более 10 сек (иногда КрипроПро ожидает ввода с клавиатуры, так мы обезопасимся)- используется утилита
expect
которая ждет, когда запускаемая программа попросит ввода пароля с клавиатуры, и шлет этот пароль echo NNNNNNNNNNNNNNNNNNNN
- отвечает 'No' на все возможные вопросы программы
- sign.sh
#!/usr/bin/env bash # Подписание файла ЭЦП # Вход: файл на STDIN, `SHA1 HASH` и `PIN` как параметры # Выход: результаты выполнения предназначены для парсинга # Для удаленного вызова необходимо настроить на сервере авторизацию по ключу SHA_HASH=$1 PIN=$2 SRC_FILE=`mktemp` DEST_FILE=$SRC_FILE.sig cat - > $SRC_FILE echo --------- CRYPTCP BEGIN --------- timeout 10s /home/sign/interface/expect-sign.sh $SHA_HASH $PIN $SRC_FILE $DEST_FILE CRYPTCP_CODE=$? echo --------- CRYPTCP END --------- if [ "$CRYPTCP_CODE" -eq "0" ]; then echo --------- CERTIFICATE SECTION BEGIN --------- CERT_FILE=`mktemp` cryptcp -nochain -copycert -thumbprint "$SHA_HASH" -f "$DEST_FILE" -df "$CERT_FILE" -der echo --------- CERTIFICATE BEGIN --------- echo CERTIFICATE SHA1: "$SHA_HASH" openssl x509 -in "$CERT_FILE" -inform der -text -noout -nameopt oneline,-esc_msb,-space_eq,sep_comma_plus echo --------- CERTIFICATE END --------- rm "$CERT_FILE" echo --------- CERTIFICATE SECTION END --------- fi echo --------- SUMMARY BEGIN --------- echo CRYPTCP CODE: $CRYPTCP_CODE echo FILE: $DEST_FILE echo --------- SUMMARY END --------- rm $SRC_FILE
- expect-sign.sh
#!/usr/bin/expect # # Обход проблемы с интерактивным вводом пароля для подписания # set timeout 3 set thumbprint [lindex $argv 0] set password [lindex $argv 1] set src_file [lindex $argv 2] set dest_file [lindex $argv 3] spawn cryptcp -sign -thumbprint $thumbprint -nochain -der $src_file $dest_file expect "Password:" { send "$password\r" } expect { "Password:" { exit 1 } "(o) OK, (c) Cancel" { send "o\r" exp_continue } eof { exit 0 } }
Добавление подписи ЭЦП в файл (в нем должны быть уже другие подписи)
- cosign.sh
#!/usr/bin/env bash # Добавление подписи ЭЦП в файл (в нем должны быть уже другие подписи) # Вход: файл на STDIN, `SHA1 HASH` и `PIN` как параметры # Выход: результаты выполнения предназначены для парсинга # Для удаленного вызова необходимо настроить на сервере авторизацию по ключу # Для текущего пользователя (sign) необходимо добавить сертификаты, # а также внести информацию по ним в БД (для работы всей схемы) SHA_HASH=$1 PIN=$2 SRC_FILE=`mktemp` cat - > $SRC_FILE cd "$(dirname "$0")" source ./lib.sh # Подписи добавляются без создания нового файла echo --------- CRYPTCP BEGIN --------- timeout 10s /home/sign/interface/expect-cosign.sh $SHA_HASH $PIN $SRC_FILE CRYPTCP_CODE=$? echo --------- CRYPTCP END --------- if [ "$CRYPTCP_CODE" -eq "0" ]; then certmgr_list if [ "$CERTMGR_CODE" -eq "0" ]; then certmgr_review fi fi echo --------- SUMMARY BEGIN --------- echo CRYPTCP CODE: $CRYPTCP_CODE echo FILE: $SRC_FILE echo --------- SUMMARY END ---------
- expect-cosign.sh
#!/usr/bin/expect # # Обход проблемы с интерактивным вводом пароля для подписания # set timeout 3 set thumbprint [lindex $argv 0] set password [lindex $argv 1] set src_file [lindex $argv 2] spawn cryptcp -addsign -thumbprint $thumbprint -nochain $src_file expect "Password:" { send "$password\r" } expect { "Password:" { exit 1 } "(o) OK, (c) Cancel" { send "o\r" exp_continue } eof { exit 0 } }
Получение неподписанного исходного файла
- unsigned.sh
#!/usr/bin/env bash # Получение неподписанного исходного файла BASE_FILE=`mktemp` SRC_FILE=$BASE_FILE.src ORIGIN_FILE=$BASE_FILE.orig FINAL_FILE="" cat - > $SRC_FILE # Получаем список сертификатов function certmgr_list() { CERTMGR_RESP=`certmgr -list -f "$SRC_FILE"` CERTMGR_CODE=$? } function digest() { echo '-------BEGIN UNSIGNED-------' echo RESULT: $RESULT echo FILE: $UNSIGNED_FILE echo '-------END UNSIGNED-------' } # *************** RUN **************** certmgr_list if [ "$CERTMGR_CODE" -eq "0" ]; then timeout 5s echo 'NNNNNNNNNNNNNNNNNNNN' | cryptcp -verify -nochain -f "$SRC_FILE" "$SRC_FILE" "$ORIGIN_FILE" UNSIGNED_FILE=$ORIGIN_FILE rm "$SRC_FILE" > /dev/null 2>&1 else UNSIGNED_FILE=$SRC_FILE rm "$ORIGIN_FILE" > /dev/null 2>&1 fi digest rm "$BASE_FILE" > /dev/null 2>&1
Получение тумбы файла
Скрипт получает картинку для предпросмотра (thumbnail) как из подписанного (самостоятельно извлекает), так и не подписанного файла. Необходимо дополнительно поставить unoconv
- thumbnail.sh
#!/usr/bin/env bash # Получение тумбы файла BASE_FILE=`mktemp` SRC_FILE=$BASE_FILE.src ORIGIN_FILE=$BASE_FILE.orig FINAL_FILE="" cat - > $SRC_FILE # Получаем список сертификатов function certmgr_list() { CERTMGR_RESP=`certmgr -list -f "$SRC_FILE" > /dev/null 2>&1` CERTMGR_CODE=$? } function thumbnail() { if [ -f "$STEP_1_FILE" ]; then timeout 10s unoconv "$STEP_1_FILE" RET_CODE=$? rm "$STEP_1_FILE" if [ "$RET_CODE" -eq "0" ]; then STEP_2_FILE=$BASE_FILE.pdf if [ -f "$STEP_2_FILE" ]; then timeout 10s unoconv -f gif "$STEP_2_FILE" RET_CODE=$? rm "$STEP_2_FILE" if [ "$RET_CODE" -eq "0" ]; then FINAL_FILE=$BASE_FILE.gif if [ -f "$FINAL_FILE" ]; then RESULT='0' else RESULT='1' fi else RESULT='1' fi else RESULT='1' fi else RESULT='1' fi else RESULT='1' # ошибка fi } function digest() { echo '-------BEGIN THUMBNAIL-------' echo RESULT: $RESULT echo FILE: $FINAL_FILE echo '-------END THUMBNAIL-------' } # *************** RUN **************** certmgr_list if [ "$CERTMGR_CODE" -eq "0" ]; then timeout 5s echo 'NNNNNNNNNNNNNNNNNNNN' | cryptcp -verify -nochain -f "$SRC_FILE" "$SRC_FILE" "$ORIGIN_FILE" STEP_1_FILE=$ORIGIN_FILE else STEP_1_FILE=$SRC_FILE fi thumbnail digest rm "$BASE_FILE" > /dev/null 2>&1 rm "$SRC_FILE" > /dev/null 2>&1 rm "$ORIGIN_FILE" > /dev/null 2>&1
Получение PDF файла для печати
Также необходима программа unoconv
- pdf.sh
#!/usr/bin/env bash # pdf для печати BASE_FILE=`mktemp` SRC_FILE=$BASE_FILE.src FINAL_FILE="" cat - > $SRC_FILE function convertToPdf { timeout 10s unoconv "$SRC_FILE" RET_CODE=$? if [ "$RET_CODE" -eq "0" ]; then FINAL_FILE=$BASE_FILE.pdf RESULT='0' else RESULT='1' fi } function digest() { echo '-------BEGIN PDF-------' echo RESULT: $RESULT echo FILE: $FINAL_FILE echo '-------END PDF-------' } convertToPdf digest rm "$BASE_FILE" > /dev/null 2>&1 rm "$SRC_FILE" > /dev/null 2>&1
lib.sh
- lib.sh
#!/usr/bin/env bash # Список общих функций # Получаем список сертификатов function certmgr_list() { CERTMGR_RESP=`certmgr -list -f "$SRC_FILE"` CERTMGR_CODE=$? if [ "$CERTMGR_CODE" -eq "0" ]; then SHAS=`echo "$CERTMGR_RESP" | grep "SHA1 Hash" | cut -f 2 -d "x"` fi } # Получаем данные сертификатов function certmgr_review() { echo --------- CERTIFICATE SECTION BEGIN --------- for SHA in $SHAS do CERT_FILE=`mktemp` cryptcp -nochain -copycert -thumbprint "$SHA" -f "$SRC_FILE" -df "$CERT_FILE" -der echo --------- CERTIFICATE BEGIN --------- echo CERTIFICATE SHA1: "$SHA" openssl x509 -in "$CERT_FILE" -inform der -text -noout -nameopt oneline,-esc_msb,-space_eq,sep_comma_plus echo --------- CERTIFICATE END --------- rm "$CERT_FILE" done echo --------- CERTIFICATE SECTION END --------- }