Initial commit

This commit is contained in:
Alexey Berezhok
2026-02-19 22:19:55 +03:00
commit c2b717bea6
45 changed files with 5099 additions and 0 deletions

230
utils/api_call.sh Executable file
View File

@@ -0,0 +1,230 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<EOF
Usage: $(basename "$0") -s SERVER -u USER -p PASS <command> [args]
Commands:
install <login> <password> <email> # Create initial admin user (no auth needed)
listserv # List server certificates
listclient # List client certificates
addserv <domains> <validity_days> # Add server certificate
addclient <server_domain> <client> <validity_days> # Add client certificate
listuser # List users
adduser <login> <password> <email> <role> # Add user (role numeric)
revokecert <id> # Revoke certificate
deleteuser <id> # Delete user
edituser <id> <login> <password> <role> # Edit user
certdetail <id> # Cert detail
rootdetail # Root cert detail
help # Show this help
Options:
-s SERVER Base URL of the API (default: http://127.0.0.1:4567)
-u USER Username for authentication
-p PASS Password for authentication
EOF
}
# Parse global options
SERVER="http://127.0.0.1:4567"
USERNAME=""
PASSWORD=""
while getopts ":s:u:p:h" opt; do
case $opt in
s) SERVER="$OPTARG" ;;
u) USERNAME="$OPTARG" ;;
p) PASSWORD="$OPTARG" ;;
h)
usage
exit 0
;;
*)
echo "Unknown option -$OPTARG"
usage
exit 1
;;
esac
done
shift $((OPTIND - 1))
COMMAND="$1"
shift
# Helper: get token
get_token() {
local login="$1"
local pass="$2"
local resp
resp=$(curl -s -X POST "$SERVER/api/v1/login" \
-H "Content-Type: application/json" \
-d "{\"login\":\"$login\",\"password\":\"$pass\"}")
local err
err=$(echo "$resp" | jq -r '.error')
if [[ "$err" != "null" && -n "$err" ]]; then
echo "Login error: $err" >&2
exit 1
fi
echo "$resp" | jq -r '.content.token'
}
# Helper: perform request
do_req() {
local method="$1"
local url="$2"
local data="$3"
local token="$4"
local json_data
if [[ -n "$token" ]]; then
json_data=$(echo "$data" | jq --arg token "$token" '. + {token: $token}')
else
json_data="$data"
fi
local resp
resp=$(curl -s -X "$method" "$url" \
-H "Content-Type: application/json" \
-d "$json_data")
local err
err=$(echo "$resp" | jq -r '.error')
if [[ "$err" != "null" && -n "$err" ]]; then
echo "Error: $err" >&2
exit 1
fi
echo "$resp" | jq -r '.content'
}
# Commands requiring authentication
auth_required_commands=("listserv" "listclient" "addserv" "addclient" "listuser" "adduser" "revokecert" "deleteuser" "edituser" "certdetail" "rootdetail")
needs_auth=false
for cmd in "${auth_required_commands[@]}"; do
if [[ "$COMMAND" == "$cmd" ]]; then
needs_auth=true
break
fi
done
if $needs_auth; then
if [[ -z "$USERNAME" || -z "$PASSWORD" ]]; then
echo "Username and password required for command '$COMMAND'" >&2
exit 1
fi
TOKEN=$(get_token "$USERNAME" "$PASSWORD")
if [[ -z "$TOKEN" ]]; then
echo "Failed to obtain token" >&2
exit 1
fi
fi
case "$COMMAND" in
install)
if [[ $# -ne 3 ]]; then
echo "install requires <login> <password> <email>" >&2
exit 1
fi
login="$1"
pw="$2"
email="$3"
do_req POST "$SERVER/api/v1/adduser" "{\"login\":\"$login\",\"password\":\"$pw\",\"email\":\"$email\",\"role\":1}" ""
;;
listserv)
do_req POST "$SERVER/api/v1/servers" "{}" "$TOKEN"
;;
listclient)
do_req POST "$SERVER/api/v1/clients" "{}" "$TOKEN"
;;
addserv)
if [[ $# -ne 2 ]]; then
echo "addserv requires <domains> <validity_days>" >&2
exit 1
fi
domains="$1"
days="$2"
do_req POST "$SERVER/api/v1/addserver" "{\"domains\":\"$domains\",\"validity_days\":$days}" "$TOKEN"
;;
addclient)
if [[ $# -ne 3 ]]; then
echo "addclient requires <server_domain> <client> <validity_days>" >&2
exit 1
fi
server_domain="$1"
client="$2"
validity_days="$3"
do_req POST "$SERVER/api/v1/addclient" "{\"server_domain\":\"$server_domain\",\"client\":\"$client\",\"validity_days\":\"$validity_days\"}" "$TOKEN"
;;
listuser)
do_req POST "$SERVER/api/v1/ulist" "{}" "$TOKEN"
;;
adduser)
if [[ $# -ne 4 ]]; then
echo "adduser requires <login> <password> <email> <role:user|creator|admin>" >&2
exit 1
fi
login="$1"
pw="$2"
email="$3"
role="$4"
case "$role" in
user) role=0 ;;
creator) role=1 ;;
admin) role=2 ;;
*) role=0 ;;
esac
do_req POST "$SERVER/api/v1/adduser" "{\"login\":\"$login\",\"password\":\"$pw\",\"email\":\"$email\",\"role\":$role}" "$TOKEN"
;;
revokecert)
if [[ $# -ne 1 ]]; then
echo "revokecert requires <id>" >&2
exit 1
fi
id="$1"
do_req POST "$SERVER/api/v1/revoke/$id" "{}" "$TOKEN"
;;
deleteuser)
if [[ $# -ne 1 ]]; then
echo "deleteuser requires <id>" >&2
exit 1
fi
id="$1"
do_req POST "$SERVER/api/v1/deleteuser/$id" "{}" "$TOKEN"
;;
edituser)
if [[ $# -ne 5 ]]; then
echo "edituser requires <id> <login> <password> <email> <role: user|creator|admin>" >&2
exit 1
fi
id="$1"
login="$2"
pw="$3"
role="$5"
email="$4"
case "$role" in
user) role=0 ;;
creator) role=1 ;;
admin) role=2 ;;
*) role=0 ;;
esac
do_req POST "$SERVER/api/v1/edituser/$id" "{\"login\":\"$login\",\"password\":\"$pw\",\"role\":$role,\"email\":\"$email\"}" "$TOKEN"
;;
certdetail)
if [[ $# -ne 1 ]]; then
echo "certdetail requires <id>" >&2
exit 1
fi
id="$1"
do_req POST "$SERVER/api/v1/certinfo/$id" "{}" "$TOKEN"
;;
rootdetail)
do_req POST "$SERVER/api/v1/root" "{}" "$TOKEN"
;;
help | --help | -h)
usage
;;
*)
echo "Unknown command: $COMMAND" >&2
usage
exit 1
;;
esac

28
utils/config.sh Normal file
View File

@@ -0,0 +1,28 @@
#!/bin/bash
if [ -e custom_config.sh ]; then
source custom_config.sh
else
ROOT_DIR="."
COUNTRY_NAME="RU"
ORG_NAME="Regenal Organization"
COMM_NAME="General Name"
SERT_PASS=""
fi
if [ -z "$SERT_PASS" ]; then
if [[ "$LANG" =~ ^ru ]]; then
echo "Установите пароль для корневого сертификата и промежуточного"
else
echo "Please set a password for the root certificate and intermediate"
fi
exit 1
fi
PATH_TO_CA="$ROOT_DIR/ca"
ROOT_CA="$PATH_TO_CA/root"
IMM_CA="$PATH_TO_CA/intermediate"
CLI_CA="$PATH_TO_CA/client_certs"

41
utils/make_app_keys.sh Normal file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
# Описание: Этот скрипт генерирует беспарольный публичный и приватный ключ с помощью openssl.
# Путь к файлу указывается в первом обязательном параметре, если он не указан,
# то показывается help или usage. Если путь не существует, то сообщает об ошибке и завершает работу.
# Определяем язык вывода
if [[ "$LANG" =~ ^ru|RU ]]; then
USE_RU=1
else
USE_RU=0
fi
if [ -z "$1" ] || [ ! -e "$1" ]; then
if [ "$USE_RU" -eq 1 ]; then
echo "Использование: $0 <путь>"
else
echo "Usage: $0 <path>"
fi
exit 1
fi
PATH_TO_KEYS=$1
if [ ! -e "$PATH_TO_KEYS" ]; then
if [ "$USE_RU" -eq 1 ]; then
echo "Такого пути $PATH_TO_KEYS не существует"
else
echo "Path $PATH_TO_KEYS does not exist"
fi
exit 1
fi
openssl genpkey -algorithm RSA -out "$PATH_TO_KEYS/caapp.private.key.pem" -pkeyopt rsa_keygen_bits:2048
openssl rsa -in "$PATH_TO_KEYS/caapp.private.key.pem" -pubout -out "$PATH_TO_KEYS/caapp.public.key.pem"
if [ "$USE_RU" -eq 1 ]; then
echo "Беспарольный публичный $PATH_TO_KEYS/caapp.public.key.pem и приватный $PATH_TO_KEYS/caapp.private.key.pem ключи созданы по пути"
else
echo "Passwordless public key $PATH_TO_KEYS/caapp.public.key.pem and private key $PATH_TO_KEYS/caapp.private.key.pem created at path"
fi

182
utils/make_client_cert.sh Normal file
View File

@@ -0,0 +1,182 @@
#!/bin/bash
#
# Скрипт для создания клиентских сертификатов для указанного сервера и клиента.
# Генерирует приватный ключ, запрос на сертификат (CSR), подписывает его и выводит информацию о сгенерированном сертификате.
#
source config.sh
CURRENT_DIR=$(pwd)
# Determine language based on locale
if [[ "$LANG" =~ ^ru ]]; then
USE_RU=true
else
USE_RU=false
fi
msg() {
if $USE_RU; then
printf '%s\n' "$1"
else
printf '%s\n' "$2"
fi
}
# Проверка наличия и валидации параметров командной строки
while getopts "s:c:d:h" opt; do
case $opt in
s) server=$OPTARG ;;
c) client=$OPTARG ;;
d) days=$OPTARG ;;
h)
msg "Использование: $0 -s <доменное имя сервера> -c <строка имени клиента> -d <число дней>" "Usage: $0 -s <server domain> -c <client name string> -d <number of days>"
exit 0
;;
\?)
msg "Неверный аргумент или пустой параметр" "Invalid argument or empty parameter" >&2
msg "Использование: $0 -s <доменное имя сервера> -c <строка имени клиента> -d <число дней>" "Usage: $0 -s <server domain> -c <client name string> -d <number of days>" >&2
exit 1
;;
esac
done
# Если параметры -d и -c не заданы или пусты, вывести сообщение об ошибке и справку
if [[ -z "$server" || -z "$client" ]]; then
msg "Неверные аргументы или пустые параметры" "Invalid arguments or empty parameters" >&2
msg "Использование: $0 -s <доменное имя сервера> -c <строка имени клиента> -d <число дней>" "Usage: $0 -s <server domain> -c <client name string> -d <number of days>" >&2
exit 1
fi
# Если параметр -d не задан, принять число дней равным 30
if [ -z "$days" ]; then
days=30
fi
if [ ! -e "$PATH_TO_CA/server_certs/$server" ]; then
msg "Данного ресурса не существует $server" "Resource $server does not exist" >&2
exit 1
fi
pushd $PATH_TO_CA || {
msg "Ошибка: Не удалось перейти в каталог $PATH_TO_CA" "Error: Could not change directory to $PATH_TO_CA" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
mkdir -p client_certs
pushd client_certs || {
msg "Ошибка: Не удалось перейти в каталог client_certs" "Error: Could not change directory to client_certs" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
SEQ="1"
if [ ! -e "$server/${client}_csr_req.cnf" ]; then
mkdir -p "$server" "$server/private"
chmod 0700 "$server/private"
echo -n "2" >"$server/${client}_seq.seq"
cat <<EOF >"$server/${client}_csr_req.cnf"
[req]
default_bits = 2048
default_md = sha256
prompt = no
distinguished_name = dn
req_extensions = req_ext
[dn]
CN = $server
O = $client:1
[req_ext]
subjectAltName = @alt_names
[alt_names]
email.1 = $client
EOF
# Создание запроса на сертификат (CSR) для указанного сервера и клиента
openssl req -new -sha256 -nodes -keyout "$CLI_CA/$server/private/${client}_private.key.pem" -out "$CLI_CA/$server/${client}.csr.pem.$SEQ" -config "$CLI_CA/$server/${client}_csr_req.cnf" || {
msg "Error: Failed to create CSR for server certificate" "Error: Failed to create CSR for server certificate" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
chmod 0400 "$CLI_CA/$server/private/${client}_private.key.pem"
else
# Чтение файла "$server/${client}_seq.seq" и его значение сохраняется в переменной SEQ, а в файл без переноса строки записывается новое значение SEQ+1
SEQ=$(cat "$server/${client}_seq.seq")
echo $((SEQ + 1)) >"$server/${client}_seq.seq"
# Парсинг файла "$server/${client}_csr_req.cnf" и замена значения ключа O на $client:$SEQ
sed -i "s/^O = .*/O = $client:$SEQ/" "$server/${client}_csr_req.cnf"
openssl req -new -sha256 -key "$CLI_CA/$server/private/${client}_private.key.pem" -out "$CLI_CA/$server/${client}.csr.pem.$SEQ" -config "$CLI_CA/$server/${client}_csr_req.cnf" || {
msg "Error: Failed to create CSR for server certificate" "Error: Failed to create CSR for server certificate" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
fi
popd || {
msg "Ошибка: Не удалось вернуться из каталога client_certs" "Error: Could not popd from client_certs" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
pushd "$IMM_CA" || {
msg "Ошибка: Не удалось перейти в каталог $IMM_CA" "Error: Could not change directory to $IMM_CA" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
# Подпись CSR сертификатом CA
openssl ca -batch -config "immissuer.conf" -extensions client_cert -days "$days" -notext -md sha256 -in "$CLI_CA/$server/${client}.csr.pem.$SEQ" -out "$CLI_CA/$server/${client}.cert.pem.$SEQ" -passin "pass:$SERT_PASS" || {
msg "Ошибка: Не удалось подписать сертификат сервера" "Error: Failed to sign the server certificate" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
chmod 644 "$CLI_CA/$server/${client}.cert.pem.$SEQ"
# Вывод информации о сгенерированном сертификате
openssl x509 -noout -text -in "$CLI_CA/$server/${client}.cert.pem.$SEQ" || {
msg "Ошибка: Не удалось отобразить информацию о сертификате сервера" "Error: Failed to display the server certificate information" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
if $USE_RU; then
cat <<EOF
Сгенерированный набор ключей для установки на машину клиента для доступа:
- [OUTPUTDATA] приватный ключ: \`$CLI_CA/$server/private/${client}_private.key.pem\`;
- [OUTPUTDATA_CERT] сертификат сервера: \`$CLI_CA/$server/${client}.cert.pem.$SEQ\`;
- [OUTPUTDATA] цепочка CA: \`$IMM_CA/certs/ca-chain.cert.pem\`.
EOF
else
cat <<EOF
Generated key set for client machine:
- [OUTPUTDATA] private key: \`$CLI_CA/$server/private/${client}_private.key.pem\`;
- [OUTPUTDATA_CERT] server certificate: \`$CLI_CA/$server/${client}.cert.pem.$SEQ\`;
- [OUTPUTDATA] CA chain: \`$IMM_CA/certs/ca-chain.cert.pem\`.
EOF
fi
popd || {
msg "Ошибка: Не удалось вернуться из каталога $IMM_CA" "Error: Could not popd from $IMM_CA" >&2
cd "$CURRENT_DIR" || exit
exit 1
}
popd || {
msg "Ошибка: Не удалось вернуться из каталога $PATH_TO_CA" "Error: Could not popd from $PATH_TO_CA" >&2
cd "$CURRENT_DIR" || exit
exit 1
}

View File

@@ -0,0 +1,96 @@
#!/bin/bash
source config.sh
CURRENT_DIR=$(pwd)
CERT_REV=""
# Language detection
if [[ "$LANG" == ru_* || "$LANG" == *ru* ]]; then
IS_RU=1
else
IS_RU=0
fi
msg() {
local ru=$1
local en=$2
if [[ $IS_RU -eq 1 ]]; then
echo "$ru"
else
echo "$en"
fi
}
# Проверка наличия и валидации параметров командной строки
while getopts "s:c:n:h" opt; do
case $opt in
s) server=$OPTARG ;;
c) client=$OPTARG ;;
n) CERT_REV=$OPTARG ;;
h)
msg "Использование: $0 -s <доменное имя сервера> -c <строка имени клиента> -n <номер версии>" "Usage: $0 -s <server domain> -c <client name> -n <version number>"
exit 0
;;
\?)
msg "Неверный аргумент или пустой параметр" "Invalid argument or empty parameter" >&2
msg "Использование: $0 -s <доменное имя сервера> -c <строка имени клиента> -n <номер версии>" "Usage: $0 -s <server domain> -c <client name> -n <version number>" >&2
exit 1
;;
esac
done
# Если параметры -d и -c не заданы или пусты, вывести сообщение об ошибке и справку
if [[ -z "$server" || -z "$client" ]]; then
msg "Неверные аргументы или пустые параметры" "Invalid arguments or empty parameters" >&2
msg "Использование: $0 -s <доменное имя сервера> -c <строка имени клиента> -n <номер версии>" "Usage: $0 -s <server domain> -c <client name> -n <version number>" >&2
exit 1
fi
if [ ! -e "$PATH_TO_CA/server_certs/$server" ]; then
msg "Данного ресурса не существует $server" "Resource does not exist: $server" >&2
exit 1
fi
if [ ! -e "$CLI_CA/$server/${client}_csr_req.cnf" ]; then
msg "Данного клиента не существует $client" "Client does not exist: $client" >&2
exit 1
fi
pushd "$IMM_CA" || {
msg "Ошибка: не удалось перейти в каталог $IMM_CA" "Error: Could not change directory to $IMM_CA" >&2
cd "$CURRENT_DIR" || exit 1
}
if [ -z "$CERT_REV" ]; then
files=("$CLI_CA/$server/${client}.cert.pem".*)
else
files=("$CLI_CA/$server/${client}.cert.pem.$CERT_REV")
fi
for file in "${files[@]}"; do
if [ -e "$file" ]; then
if ! openssl ca -config "immissuer.conf" -revoke "$file" -passin "pass:$SERT_PASS"; then
msg "Ошибка при выполнении команды openssl ca -revoke" "Error executing openssl ca -revoke" >&2
cd "$CURRENT_DIR" || exit 1
fi
fi
done
if ! openssl ca -config "immissuer.conf" -gencrl -out crl/intermediate.crl.pem -passin "pass:$SERT_PASS"; then
msg "Ошибка при выполнении команды openssl ca -gencrl" "Error executing openssl ca -gencrl" >&2
cd "$CURRENT_DIR" || exit 1
fi
if ! openssl crl -in crl/intermediate.crl.pem -noout -text; then
msg "Ошибка при выполнении команды openssl crl" "Error executing openssl crl" >&2
cd "$CURRENT_DIR" || exit 1
fi
cat $ROOT_CA/crl/ca.crl.pem $IMM_CA/crl/intermediate.crl.pem >$IMM_CA/crl/ca-full.crl.pem
popd || {
msg "Ошибка: не удалось выйти из каталога $IMM_CA" "Error: Could not popd from $IMM_CA" >&2
cd "$CURRENT_DIR" || exit 1
}

209
utils/make_server_cert.sh Normal file
View File

@@ -0,0 +1,209 @@
#!/bin/bash
# Этот скрипт предназначен для генерации серверных сертификатов для указанных доменов или IP-адресов.
# Он создает приватный ключ, запрос на подпись сертификата (CSR) и сам сертификат,
# используя конфигурационные файлы и инфраструктуру центра сертификации (CA).
# Скрипт также выводит информацию о сгенерированных ключах и сертификатах.
source ./config.sh
# Определяем, установлена ли русская локаль
if [[ "${LANG,,}" == ru* ]] || [[ "${LC_MESSAGES,,}" == ru* ]]; then
LANG_RU=1
else
LANG_RU=0
fi
# Handle -h option for help message
if [ "$1" == "-h" ]; then
if [ "$LANG_RU" -eq 1 ]; then
echo "Использование: $0 [-h] [-t|--days DAYS] [domain1, domain2, ...]"
echo "Создает сертификаты сервера для указанных доменов или IP."
echo
echo "Опции:"
echo " -h Показать это сообщение"
echo " -t|--days DAYS Установить срок действия сертификата (по умолчанию: 3650 дней)"
else
echo "Usage: $0 [-h] [-t|--days DAYS] [domain1, domain2, ...]"
echo "Generate server certificates for the given domains or IPs."
echo
echo "Options:"
echo " -h Display this help message"
echo " -t|--days DAYS Set the number of days the certificate is valid for (default: 3650)"
fi
exit 0
fi
# Чтение параметра -t через getopt для установки числа дней действия сертификата
while true; do
case "$1" in
-t | --days)
CERT_DAYS="$2"
shift 2
break
;;
-h | --help)
if [ "$LANG_RU" -eq 1 ]; then
echo "Использование: $0 [-h] [-t|--days DAYS] [domain1, domain2, ...]"
echo "Создает сертификаты сервера для указанных доменов или IP."
echo
echo "Опции:"
echo " -h Показать это сообщение"
echo " -t|--days DAYS Установить срок действия сертификата (по умолчанию: 3650 дней)"
else
echo "Usage: $0 [-h] [-t|--days DAYS] [domain1, domain2, ...]"
echo "Generate server certificates for the given domains or IPs."
echo
echo "Options:"
echo " -h Display this help message"
echo " -t|--days DAYS Set the number of days the certificate is valid for (default: 3650)"
fi
exit 0
;;
*) break ;;
esac
done
# Если параметр не указан, используем значение по умолчанию
CERT_DAYS=${CERT_DAYS:-3650}
pushd $PATH_TO_CA || exit
mkdir -p server_certs
pushd server_certs || exit
# Проверка, предоставлен ли первый параметр и не пуст ли он
if [ -z "$1" ]; then
if [ "$LANG_RU" -eq 1 ]; then
echo "Нет входных данных"
else
echo "No input provided"
fi
exit 0
fi
# Разделение входной строки в массив с использованием запятых или пробелов как разделителей
IFS=', ' read -r -a items <<<"$1"
# Проверка, есть ли хотя бы один элемент в списке
if [ "${#items[@]}" -eq 0 ]; then
if [ "$LANG_RU" -eq 1 ]; then
echo "Входные данные пусты"
else
echo "No elements found in the input"
fi
popd || exit
popd || exit
exit 0
fi
SEQ="1"
# Извлечение первого элемента списка
fst_elem="${items[0]}"
# Создание директории с именем первого элемента, если она не существует
mkdir -p "$fst_elem" || true
if [ ! -e "$fst_elem/csr_req.cnf" ]; then
echo -n "2" >"$fst_elem/${fst_elem}_seq.seq"
# Создание файла csr_api.cnf с необходимым содержимым
cat <<EOF >"$fst_elem/csr_req.cnf"
[req]
default_bits = 2048
default_md = sha256
prompt = no
distinguished_name = dn
req_extensions = req_ext
[dn]
CN = $fst_elem
O = ${ORG_NAME}:$SEQ
[req_ext]
subjectAltName = @alt_names
[alt_names]
EOF
# Добавление записей DNS для доменных имен и записей IP для IP-адресов
dns_count=1
ip_count=1
for item in "${items[@]}"; do
if [[ "$item" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "IP.$ip_count = $item" >>"$fst_elem/csr_req.cnf"
((ip_count++))
else
echo "DNS.$dns_count = $item" >>"$fst_elem/csr_req.cnf"
((dns_count++))
fi
done
popd || exit
pushd "$IMM_CA" || {
if [ "$LANG_RU" -eq 1 ]; then
echo "Ошибка: не удалось перейти в каталог $IMM_CA"
else
echo "Error: Could not change directory to $IMM_CA"
fi
exit 1
}
openssl genrsa -out "private/$fst_elem.key.pem" -passout "pass:$SERT_PASS" 2048
chmod 400 "private/$fst_elem.key.pem"
else
SEQ=$(cat "$fst_elem/${fst_elem}_seq.seq")
echo $((SEQ + 1)) >"$fst_elem/${fst_elem}_seq.seq"
sed -i "s/^O = .*/O = ${ORG_NAME}:${SEQ}/" "${fst_elem}/csr_req.cnf"
pushd "$IMM_CA" || {
if [ "$LANG_RU" -eq 1 ]; then
echo "Ошибка: не удалось перейти в каталог $IMM_CA"
else
echo "Error: Could not change directory to $IMM_CA"
fi
exit 1
}
fi
# Генерация запроса на подпись сертификата (CSR)
openssl req -new -sha256 -key "private/$fst_elem.key.pem" -out "csr/$fst_elem.csr.pem" -config "../server_certs/$fst_elem/csr_req.cnf"
# Подписание CSR и создание сертификата
openssl ca -batch -config "immissuer.conf" -extensions server_cert -days "$CERT_DAYS" -notext -md sha256 -in "csr/$fst_elem.csr.pem" -out "certs/$fst_elem.cert.pem.$SEQ" -passin "pass:$SERT_PASS"
chmod 444 "certs/$fst_elem.cert.pem.$SEQ"
# Вывод информации о сертификате
openssl x509 -noout -text -in "certs/$fst_elem.cert.pem.$SEQ"
# Информирование пользователя о сгенерированных ключах и сертификатах
if [ "$LANG_RU" -eq 1 ]; then
cat <<EOF
Сгенерированный набор ключей для установки на сервер:
- [OUTPUTDATA] приватный ключ: \`$IMM_CA/private/$fst_elem.key.pem\`;
- [OUTPUTDATA_CERT] сертификат сервера: \`$IMM_CA/certs/$fst_elem.cert.pem.$SEQ\`;
- [OUTPUTDATA] цепочка CA: \`$IMM_CA/certs/ca-chain.cert.pem\`;
- [OUTPUTDATA] список отмененных сертификатов: \`$IMM_CA/crl/ca-full.crl.pem\`
EOF
else
cat <<EOF
Generated key set for server installation:
- [OUTPUTDATA] private key: \`$IMM_CA/private/$fst_elem.key.pem\`;
- [OUTPUTDATA_CERT] server certificate: \`$IMM_CA/certs/$fst_elem.cert.pem.$SEQ\`;
- [OUTPUTDATA] CA chain: \`$IMM_CA/certs/ca-chain.cert.pem\`;
- [OUTPUTDATA] revoked certificates list: \`$IMM_CA/crl/ca-full.crl.pem\`
EOF
fi
popd || exit
popd || exit

View File

@@ -0,0 +1,90 @@
#!/bin/bash
source config.sh
CURRENT_DIR=$(pwd)
CERT_REV=""
# Detect language: Russian if LANG or LC_ALL starts with 'ru'
if [[ "${LANG:-$LC_ALL}" =~ ^ru|^ru_RU ]]; then
IS_RUSSIAN=1
else
IS_RUSSIAN=0
fi
# Helper to print messages in the appropriate language
msg() {
local en="$1"
local ru="$2"
if [ "$IS_RUSSIAN" -eq 1 ]; then
echo "$ru"
else
echo "$en"
fi
}
# Проверка наличия и валидации параметров командной строки
while getopts "s:n:h" opt; do
case $opt in
s) server=$OPTARG ;;
n) CERT_REV=$OPTARG ;;
h)
msg "Usage: $0 -s <server domain name> -n <certificate reverse number>" "Использование: $0 -s <доменное имя сервера> -n <реверс-номер сертификата>"
exit 0
;;
\?)
msg "Invalid argument or missing parameter" "Неверный аргумент или пустой параметр" >&2
msg "Usage: $0 -s <server domain name> -n <certificate reverse number>" "Использование: $0 -s <доменное имя сервера> -n <реверс-номер сертификата>" >&2
exit 1
;;
esac
done
if [ -z "$server" ]; then
msg "Invalid arguments or missing parameters" "Неверные аргументы или пустые параметры" >&2
msg "Usage: $0 -s <server domain name> -n <certificate reverse number>" "Использование: $0 -s <доменное имя сервера> -n <реверс-номер сертификата>" >&2
exit 1
fi
if [ ! -e "$PATH_TO_CA/server_certs/$server" ]; then
msg "Resource does not exist $server" "Данного ресурса не существует $server" >&2
exit 1
fi
pushd "$IMM_CA" || {
msg "Error: Could not change directory to $IMM_CA" "Ошибка: Не удалось перейти в каталог $IMM_CA" >&2
cd "$CURRENT_DIR" || exit 1
}
if [ -z "$CERT_REV" ]; then
files=("certs/$server.cert.pem".*)
else
files=("certs/$server.cert.pem.$CERT_REV")
fi
for file in "${files[@]}"; do
if [ -e "$file" ]; then
if ! openssl ca -config "immissuer.conf" -revoke "$file" -passin "pass:$SERT_PASS"; then
msg "Error executing openssl ca -revoke ($file)" "Ошибка при выполнении команды openssl ca -revoke ($file)" >&2
cd "$CURRENT_DIR" || exit 1
fi
fi
done
if ! openssl ca -config "immissuer.conf" -gencrl -out crl/intermediate.crl.pem -passin "pass:$SERT_PASS"; then
msg "Error executing openssl ca -gencrl" "Ошибка при выполнении команды openssl ca -gencrl" >&2
cd "$CURRENT_DIR" || exit 1
fi
if ! openssl crl -in crl/intermediate.crl.pem -noout -text; then
msg "Error executing openssl crl" "Ошибка при выполнении команды openssl crl" >&2
cd "$CURRENT_DIR" || exit 1
fi
cat $ROOT_CA/crl/ca.crl.pem $IMM_CA/crl/intermediate.crl.pem >$IMM_CA/crl/ca-full.crl.pem
popd || {
msg "Error: Could not popd from $IMM_CA" "Ошибка: Не удалось выполнить popd из $IMM_CA" >&2
cd "$CURRENT_DIR" || exit 1
}

279
utils/prepare.sh Normal file
View File

@@ -0,0 +1,279 @@
#!/bin/bash
# Этот скрипт автоматизирует процесс создания инфраструктуры центра сертификации (ЦС),
# включая создание директорий, генерацию ключей и сертификатов,
# а также настройку конфигурационных файлов для корневого и промежуточного ЦА.
#
# Скрипт выполняет следующие основные действия:
# 1. Создает необходимые директории для хранения сертификатов, ключей и других файлов ЦС.
# 2. Генерирует RSA ключи для корневого и промежуточного ЦА с шифрованием AES-256.
# 3. Создает самоподписанный корневой сертификат и CSR (Certificate Signing Request)
# для промежуточного ЦА.
# 4. Подписывает сертификат промежуточного ЦА корневым ЦА.
# 5. Создает цепочку сертификатов, включающую корневой и промежуточный сертификаты.
# 6. Проверяет целостность созданного сертификата промежуточного ЦА с помощью корневого ЦА.
#
# Для использования скрипта рекомендуется запускать его с правами суперпользователя (root),
# так как он создает файлы и директории в защищенных системных папках.
#set -e
#trap 'echo "Error: Script execution failed"; exit 1' ERR
source ./config.sh
# Detect language and define error function
LANGUAGE="en"
if [[ "$LANG" == ru* || "$LANG" == *ru_* || "$LC_ALL" == ru* || "$LC_ALL" == *ru_* ]]; then
LANGUAGE="ru"
fi
msg() {
local en_msg="$1"
local ru_msg="$2"
if [[ "$LANGUAGE" == "ru" ]]; then
echo "$ru_msg"
else
echo "$en_msg"
fi
exit 1
}
# Проверка переменной VAL_DAYS
if [[ -z "$VAL_DAYS" || ! "$VAL_DAYS" =~ ^[0-9]+$ || "$VAL_DAYS" -le 0 ]]; then
msg "Error: VAL_DAYS must be a positive integer" "Ошибка: Переменная VAL_DAYS должна быть положительным целым числом"
fi
if ! mkdir -m 700 "$PATH_TO_CA"; then
msg "Error: Failed to create directory $PATH_TO_CA" "Ошибка: Не удалось создать директорию $PATH_TO_CA"
fi
# Перейти в директорию CA или выйти с ошибкой, если это не удалось
cd "$PATH_TO_CA" || { msg "Error: Failed to change directory to $PATH_TO_CA" "Ошибка: Не удалось перейти в каталог $PATH_TO_CA"; }
# Список каталогов, для которых создается структура
DIRECTORIES=("root" "intermediate")
# Создание необходимых директорий и настройка их прав доступа
for dir in "${DIRECTORIES[@]}"; do
# Создание поддиректорий в каждой директории из списка
mkdir -p "$dir/certs" "$dir/crl" "$dir/newcerts" "$dir/private" "$dir/csr"
chmod 700 "$dir/private"
# Создание файлов базы CA
touch "$dir/index.txt"
echo -n 100000 >"$dir/serial"
# Настройка файла для CRL (список отозванных сертификатов)
echo -n 100000 >"$dir/crlnumber"
done
# Создание конфигурационного файла для корневого ЦА
cat >root/sertissuer.conf <<EOL
[ca]
default_ca=CA_default
[CA_default]
dir = $ROOT_CA
certs = \$dir/certs
crl_dir = \$dir/crl
database = \$dir/index.txt
new_certs_dir = \$dir/newcerts
serial = \$dir/serial
certificate = \$dir/certs/ca.cert.pem
private_key = \$dir/private/ca.key.pem
crlnumber = \$dir/crlnumber
crl = \$dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = $VAL_DAYS
preserve = no
policy = policy_strict
[policy_strict]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[req]
default_bits = 4096
default_md = sha256
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
string_mask = utf8only
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
countryName = $COUNTRY_NAME
organizationName = $ORG_NAME
commonName = $ORG_NAME
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, keyCertSign, cRLSign
[v3_inter]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, keyCertSign, cRLSign
[crl_ext]
authorityKeyIdentifier = keyid:always
EOL
# Перейти в директорию корневого ЦА или выйти с ошибкой, если это не удалось
pushd "$ROOT_CA" || { msg "Error: Failed to change directory to $ROOT_CA" "Ошибка: Не удалось перейти в каталог $ROOT_CA"; }
# Генерация RSA ключа для корневого ЦА с шифрованием AES-256
openssl genrsa -aes256 -out private/ca.key.pem -passout "pass:$SERT_PASS" 4096 || { msg "Error: Failed to generate RSA key for root CA" "Ошибка: Не удалось создать RSAключ для корневого ЦА"; }
# Установка прав доступа для ключа корневого ЦА
chmod 400 private/ca.key.pem
# Создание самоподписанного сертификата корневого ЦА
openssl req -config sertissuer.conf -key private/ca.key.pem -new -x509 -days "$VAL_DAYS" -sha256 -extensions v3_ca -out certs/ca.cert.pem -passin "pass:$SERT_PASS" || { msg "Error: Failed to create root CA certificate" "Ошибка: Не удалось создать сертификат корневого ЦА"; }
# Установка прав доступа для сертификата корневого ЦА
chmod 444 certs/ca.cert.pem
# Отображение деталей сертификата корневого ЦА
openssl x509 -noout -text -in certs/ca.cert.pem || { msg "Error: Failed to display root CA certificate details" "Ошибка: Не удалось вывести детали сертификата корневого ЦА"; }
# Вернуться в исходную директорию или выйти с ошибкой, если это не удалось
popd || { msg "Can't return to old directory" "Невозможно вернуться к старому каталогу"; }
# Создание конфигурационного файла для промежуточного ЦА
cat >intermediate/immissuer.conf <<EOL
[ca]
default_ca=CA_default
[CA_default]
dir = $IMM_CA
certs = \$dir/certs
crl_dir = \$dir/crl
database = \$dir/index.txt
new_certs_dir = \$dir/newcerts
serial = \$dir/serial
certificate = \$dir/certs/intermediate.cert.pem
private_key = \$dir/private/intermediate.key.pem
crlnumber = \$dir/crlnumber
crl = \$dir/crl/intermediate.crl.pem
crl_extensions = crl_ext
default_crl_days = 7
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 825
preserve = no
policy = policy_loose
[policy_loose]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[req]
default_bits = 4096
default_md = sha256
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
string_mask = utf8only
x509_extensions = v3_intermediate_ca
prompt = no
[req_distinguished_name]
countryName = $COUNTRY_NAME
organizationName = $ORG_NAME
commonName = $ORG_NAME
[v3_intermediate_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, keyCertSign, cRLSign
[server_cert]
basicConstraints = CA:false
nsCertType = server
nsComment = "$COMM_NAME TLS server cert"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[client_cert]
basicConstraints = CA:false
nsCertType = client
nsComment = "Brepo client cert"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
[crl_ext]
authorityKeyIdentifier = keyid:always
EOL
# Перейти в директорию промежуточного ЦА или выйти с ошибкой, если это не удалось
pushd "$IMM_CA" || { msg "Error: Failed to change directory to $IMM_CA" "Ошибка: Не удалось перейти в каталог $IMM_CA"; }
# Генерация RSA ключа для промежуточного ЦА с шифрованием AES-256
openssl genrsa -aes256 -out private/intermediate.key.pem -passout "pass:$SERT_PASS" 4096 || { msg "Error: Failed to generate RSA key for intermediate CA" "Ошибка: Не удалось создать RSAключ для промежуточного ЦА"; }
# Установка прав доступа для ключа промежуточного ЦА
chmod 400 private/intermediate.key.pem
# Создание CSR для промежуточного ЦА
openssl req -config immissuer.conf -new -sha256 -key private/intermediate.key.pem -out csr/intermediate.csr.pem -passin "pass:$SERT_PASS" || { msg "Error: Failed to create CSR for intermediate CA" "Ошибка: Не удалось создать запрос на сертификат для промежуточного ЦА"; }
# Вернуться в исходную директорию или выйти с ошибкой, если это не удалось
popd || { msg "Can't return to old directory" "Невозможно вернуться к старому каталогу"; }
# Перейти в директорию корневого ЦА или выйти с ошибкой, если это не удалось
pushd "$ROOT_CA" || { msg "Error: Failed to change directory to $ROOT_CA" "Ошибка: Не удалось перейти в каталог $ROOT_CA"; }
# Подпись сертификата промежуточного ЦА корневым ЦА
openssl ca -batch -config sertissuer.conf -extensions v3_inter -days 3550 -notext -md sha256 -in $IMM_CA/csr/intermediate.csr.pem -out $IMM_CA/certs/intermediate.cert.pem -passin "pass:$SERT_PASS" || { msg "Error: Failed to sign intermediate CA certificate" "Ошибка: Не удалось подписать сертификат промежуточного ЦА корневым ЦА"; }
# Установка прав доступа для сертификата промежуточного ЦА
chmod 444 $IMM_CA/certs/intermediate.cert.pem
openssl ca -config "sertissuer.conf" -gencrl -out crl/ca.crl.pem -passin "pass:$SERT_PASS"
# Вернуться в исходную директорию или выйти с ошибкой, если это не удалось
popd || { msg "Can't return to old directory" "Невозможно вернуться к старому каталогу"; }
# Перейти в директорию промежуточного ЦА или выйти с ошибкой, если это не удалось
pushd "$IMM_CA" || { msg "Error: Failed to change directory to $IMM_CA" "Ошибка: Не удалось перейти в каталог $IMM_CA"; }
openssl ca -config "immissuer.conf" -gencrl -out crl/intermediate.crl.pem -passin "pass:$SERT_PASS"
cat $ROOT_CA/crl/ca.crl.pem $IMM_CA/crl/intermediate.crl.pem >$IMM_CA/crl/ca-full.crl.pem
# Вернуться в исходную директорию или выйти с ошибкой, если это не удалось
popd || { msg "Can't return to old directory" "Невозможно вернуться к старому каталогу"; }
# Создание цепочки сертификатов
cat "$IMM_CA/certs/intermediate.cert.pem" "$ROOT_CA/certs/ca.cert.pem" >"$IMM_CA/certs/ca-chain.cert.pem" || { msg "Error: Failed to create CA chain certificate" "Ошибка: Не удалось создать цепочку сертификатов ЦА"; }
# Проверка сертификата промежуточного ЦА с использованием корневого центра сертификации
openssl verify -CAfile $ROOT_CA/certs/ca.cert.pem $IMM_CA/certs/intermediate.cert.pem || { msg "Error: Failed to verify intermediate CA certificate" "Ошибка: Не удалось проверить сертификат промежуточного ЦА"; }
exit 0