Проверки реализованы как bash-скрипты в tests/. Go-тестов (*_test.go) в проекте нет -
всё, что проверяется, требует живой базы, поднятых слушателей и реальных
криптографических операций, поэтому тесты работают против запущенного приложения.
| Скрипт | Что проверяет |
|---|---|
tests/crl/test_crl.sh |
CRL: CDP, подписант, содержимое, окно валидности, цепочка |
tests/ocsp/test_ocsp.sh |
OCSP: AIA, POST и GET, кэширование, unauthorized, статус Sub CA |
tests/est/test_est.sh |
EST: полный цикл enroll → reenroll, блокировка по max_uses |
tests/revocation/test_revocation.sh |
Сквозная сверка: база ↔ CRL ↔ OCSP |
Все скрипты сами находят корень проекта, поднимаясь вверх по дереву до go.mod,
поэтому запускаются откуда угодно:
./tests/ocsp/test_ocsp.sh
cd tests/ocsp && ./test_ocsp.shНастройки переопределяются переменными окружения: DB, BASE_URL, CRL_URL,
OCSP_URL, EST_URL. Временные файлы создаются в mktemp -d и удаляются по trap.
Требуется запущенное приложение - скрипты обращаются к живым эндпоинтам.
./tests/crl/test_crl.sh [<SERIAL>]Восемь шагов: достаёт сертификат из базы, печатает CDP, Issuer и AKI, скачивает оба
CRL, показывает их содержимое и наличие искомого серийного номера, сверяет AKI
сертификата с AKI подписанта CRL, проверяет CDP в самом Sub CA и выполняет
openssl verify -crl_check_all.
Отдельная функция check_crl_validity_window проверяет, что nextUpdate сдвинут
относительно thisUpdate и совпадает с CAcrl.updateInterval. Это регрессионный
тест: при чтении несуществующего ключа конфигурации интервал становится нулевым, и
CRL оказывается просроченным в момент выпуска.
Диагностируемые ситуации:
| Симптом | Причина |
|---|---|
AKI cert == AKI CRL signer: НЕТ |
Сертификат выпущен прежним Sub CA, который уже заменён |
unable to get certificate CRL |
У Sub CA нет CDP - выпущен до внедрения |
nextUpdate == thisUpdate |
Интервал не прочитался из конфигурации |
./tests/ocsp/test_ocsp.sh [<SERIAL>]Девять шагов: AIA в сертификате, POST-запрос с проверкой подписи ответа, GET-запрос
с base64 в пути, сверка статусов между POST и GET, заголовки кэширования,
запрос статуса Sub CA через Root CA (ветка scopeCoreSubCA) и проверка, что
неизвестный серийный номер даёт unauthorized.
URL респондера берётся из AIA самого сертификата - так проверяется, что клиент действительно найдёт респондер самостоятельно.
./tests/est/test_est.sh <username> <password> [<cn>]Требует заранее созданного EST-пользователя (раздел Add EST users). Девять шагов:
cacerts, генерация CSR, simpleenroll, проверка цепочки, simplereenroll по mTLS,
сверка смены серийного номера, проверка статусов в est_certs (старый - 2, новый -
0), состояние учётной записи и, если max_uses исчерпан, - что повторный enroll
возвращает 401.
Полный цикл проверяется на пользователе с MaxUses = 1. Скрипт использует один и тот
же CN для обоих CSR, поэтому проверка неизменности Subject проходит штатно.
./tests/revocation/test_revocation.sh [<SERIAL>]Самый строгий скрипт: сверяет три источника и возвращает ненулевой код при расхождении, поэтому пригоден для CI.
Матрица ожиданий:
cert_status |
signing_ca_id |
В CRL | В OCSP |
|---|---|---|---|
2 revoked |
0 - Core Sub CA |
да | revoked |
2 revoked |
-1 - Sub CA от Root |
да | revoked |
2 revoked |
>0 - внешний CA |
нет | revoked |
0 / 1 |
любой | нет | good |
Третья строка фиксирует принятое решение: сертификаты внешних CA исключены из нашего CRL (он подписан другим ключом и для них неприменим), но обслуживаются через OCSP.
Дополнительно сверяются причина отзыва и момент времени - время из базы,
CRL и OCSP приводится к unix-времени и сравнивается численно. Это снимает ложные
расхождения из-за представления: база хранит 2026-08-14T09:45:12+04:00, протоколы
показывают Aug 14 05:45:12 2026 GMT - один и тот же момент.
Скрипт также учитывает, что openssl дополняет серийный номер ведущим нулём до чётной длины, и сверяется с обоими вариантами записи.
# 1. Состояние до отзыва
./tests/revocation/test_revocation.sh <SERIAL> # ожидается good
# 2. Отозвать сертификат через UI
# 3. Состояние после - CRL перегенерируется сразу, ждать тика не нужно
./tests/revocation/test_revocation.sh <SERIAL> # ожидается revoked
# 4. Откатить отзыв через UI и проверить возврат
./tests/revocation/test_revocation.sh <SERIAL> # снова good# Целостность конфигурации (см. 02-configuration.md)
grep -rhoE 'viper\.Get[A-Za-z]+\("[^"]+"\)' --include="*.go" . \
| grep -oE '"[^"]+"' | tr -d '"' | sort -u
# Сборка и статический анализ
go build ./... && go vet ./... && gofmt -l .
# Синтаксис тестовых скриптов
for f in tests/*/*.sh; do bash -n "$f" && echo "OK: $f"; done