DAT
Документация

Коды ошибок

Общие коды ошибок для официально поддерживаемых DAT клиентских библиотек.

Каждому коду присвоены два значения — влияние и повтор, а некоторым дополнительно ставится метка подозрение.

Влияние — урон для сервиса

Это критерий для алертов. Смотрим только на одно: «сервис сейчас стоит или нет».

ВлияниеЗначениеПример
КритичноСервис или отдельная функция останавливается. Выдача невозможна, синхронизация окончательно провалена, инициализация не прошлаНа сервере выдачи нет ни одного пригодного сертификата
ЧастичноЧасть запросов или циклов падает, но сервис продолжает работать. Обычно восстанавливается самОдин цикл CMS провалился. Работа продолжается на прежних сертификатах
Без влиянияОдин запрос отклонён — и на этом всёПришёл подделанный токен. Отфильтровали и забыли

Без влияния — не повод для алерта. Если каждый неверный ввод обязана проверять вся дежурная смена, алерты теряют смысл.

Подозрение — расследуйте, если повторяется

Коды с меткой Подозрение в единичном случае являются частью нормальной эксплуатации. Клиент в любой момент может прислать неверное значение, и отфильтровать его — прямая обязанность библиотеки.

Но если такие ошибки идут постоянно или лавиной из одного источника, причина одна из двух.

  • Ошибка конфигурации — неверный деплой, остался клиент старой версии, сертификаты разошлись.
  • Попытка взлома — подмена токена или ключа ради прохождения проверки, либо перебор в поисках валидного значения.

Поэтому такие коды правильно вести как метрику по количеству. Оповещать имеет смысл только при превышении порога.

Повтор

ПовторЗначение
ВременноПовтор после backoff решает проблему
ПостоянноПовторять запрещено. Нужно исправить конфигурацию или ввод
СостояниеЭто сигнал, а не ошибка

Токен

Проблемы самой строки полученного токена.

DAT_TOKEN_MALFORMEDБез влиянияПостоянноshieldПодозрение

Частей, разделённых точкой, не пять; либо expire не чисто десятичное; либо cid не чисто шестнадцатеричное; либо plain или secure не base64url; либо числовое поле вышло за диапазон целого.

arrow_forwardОтклонить запрос

DAT_TOKEN_EXPIREDБез влиянияПостоянно

expire <= now. Ровно в срок — уже истёк: при expire == now токен считается просроченным.

arrow_forwardИнициировать перевыпуск токена

DAT_TOKEN_UNKNOWNЧастичноПостоянно

Ошибка токена, не попавшая ни в одну из категорий выше.

arrow_forwardПроверить логи

Истечение и ошибка формата — обязательно разные вещи

Реакции прямо противоположны: истечение — это нормальное завершение срока жизни, достаточно обновить токен; ошибка формата означает, что токен изначально не наш, и его нужно отклонить.

Разбор сначала фиксирует структуру, и только потом смотрит значения. Строка вроде "1.2.3" с нехваткой частей — это не просроченный токен, а вообще не токен, поэтому DAT_TOKEN_MALFORMED.

Знак в поле expire, например +100, — тоже ошибка формата, а не истечение. Допускаются только чистые ASCII-цифры.


Сертификат

Проблемы формата строки сертификата и того, можно ли использовать этот сертификат прямо сейчас.

DAT_CERT_MALFORMEDКритичноПостоянно

Частей, разделённых точкой, не восемь; либо не удалось разобрать cid, start, duration, ttl; либо поле ключа не base64url; либо start + duration + ttl вышло за u64.

arrow_forwardПереразвернуть сертификат

DAT_CERT_EXPIREDКритичноПостоянно

start + duration + ttl < now. Полностью истёкшее состояние: невозможны ни выдача, ни проверка.

arrow_forwardОбновить сертификат

DAT_CERT_NOT_YET_ISSUABLEКритичноВременно

now < start. Окно выдачи ещё не открылось.

arrow_forwardПодождать

DAT_CERT_ISSUANCE_ENDEDКритичноПостоянно

now > start + duration, но ttl ещё остался. Выдача невозможна, доступна только проверка.

arrow_forwardРазвернуть новый сертификат

DAT_CERT_VERIFY_ONLYКритичноПостоянно

Сертификат содержит только открытый ключ, без приватного ключа подписи. Проверка работает, выдача невозможна.

arrow_forwardПроверить настройки деплоя

DAT_CERT_NOT_FOUNDБез влиянияПостоянноshieldПодозрение

Сертификата, соответствующего cid из токена, нет в наличии. Это подделанный токен либо неверный деплой.

arrow_forwardОтклонить запрос

DAT_CERT_NOT_SYNCEDЧастичноВременно

Этот cid ещё не получен из CMS. Возникает ненадолго сразу после развёртывания нового сертификата.

arrow_forwardПовторить после синхронизации

DAT_CERT_DUPLICATE_CIDКритичноПостоянно

В импортируемом списке один и тот же cid встречается дважды или более.

arrow_forwardПроверить ответ сервера

DAT_CERT_UNKNOWNЧастичноПостоянно

Ошибка сертификата, не попавшая ни в одну из категорий выше.

arrow_forwardПроверить логи

DAT_CERT_NOT_FOUND и DAT_CERT_NOT_SYNCED внешне выглядят одинаково, но реакции разные. В первом случае это cid, который мы никогда не выпускали, — ожидание не поможет; во втором достаточно дождаться синхронизации.

Единичный DAT_CERT_NOT_FOUND достаточно просто отфильтровать, но резкий рост означает, что деплой разошёлся либо ходят поддельные токены.


Подпись

DAT_SIG_MISMATCHБез влиянияПостоянноshieldПодозрение

Проверка подписи завершилась несовпадением. Значение HMAC отличается либо ECDSA verify вернул false.

arrow_forwardЗаблокировать сессию, записать в security-лог

DAT_SIG_MALFORMEDБез влиянияПостоянноshieldПодозрение

Часть с подписью пуста; либо не base64url; либо длина ECDSA r‖s не соответствует кривой; либо не удалось преобразование в DER.

arrow_forwardОтклонить запрос

DAT_SIG_KEY_MISSINGКритичноПостоянно

Попытка подписать ключом verify-only. В рантайме приватного ключа нет.

arrow_forwardПроверить настройки сервера выдачи

DAT_SIG_BACKENDЧастичноПостоянно

Сама операция подписи или проверки не смогла выполниться. Неверный тип ключа, освобождённый handle, внутренняя ошибка криптобиблиотеки.

arrow_forwardПроверить тип ключа и библиотеку

DAT_SIG_UNKNOWNЧастичноПостоянно

Ошибка подписи, не попавшая ни в одну из категорий выше.

arrow_forwardПроверить логи

Не смешивайте несовпадение и отказ бэкенда

У этих двух кодов оси прямо противоположны.

  • DAT_SIG_MISMATCH — пришедшая подпись просто не совпала, поэтому влияния на сервис нет, зато при повторении это повод для подозрения.
  • DAT_SIG_BACKEND — сама операция проверки не отработала, то есть это наша проблема, и к подозрениям она не относится.

Если сообщать о неверном типе ключа или баге библиотеки как о «несовпадении подписи», то ситуация со сломанным собственным кодом попадёт в метрики атак. И наоборот: если настоящая подделка классифицируется как ошибка бэкенда, она целиком выпадет из метрик подозрений.


Шифрование

Проблемы шифрования и расшифровки полезной нагрузки secure.

DAT_CRYPTO_TAG_MISMATCHБез влиянияПостоянноshieldПодозрение

Тег аутентификации AES-GCM не совпадает. Либо secure был изменён, либо ключ сертификата другой.

arrow_forwardЗаблокировать сессию, записать в security-лог

DAT_CRYPTO_DATA_INVALIDБез влиянияПостоянноshieldПодозрение

Шифротекст не пуст, но короче или равен IV (12 байт); либо вход превысил предел реализации (INT_MAX и т. п.).

arrow_forwardОтклонить запрос

DAT_CRYPTO_BACKENDЧастичноПостоянно

Операция шифрования или расшифровки не смогла выполниться. Платформа без поддержки GCM либо сбой инициализации контекста.

arrow_forwardПроверить поддержку платформы

DAT_CRYPTO_UNKNOWNЧастичноПостоянно

Ошибка шифрования или расшифровки, не попавшая ни в одну из категорий выше.

arrow_forwardПроверить логи

Пустая полезная нагрузка secure не является ошибкой. Пустой вход даёт пустой выход и не порождает никакого кода.

На пути, где проверка подписи пропускается, тег GCM — единственная проверка целостности. Поэтому DAT_CRYPTO_TAG_MISMATCH не объединяется одним кодом с остальными сбоями расшифровки.


Ключ

DAT_KEY_INVALIDБез влиянияПостоянноshieldПодозрение

Длина ключа не соответствует заявленному алгоритму (HMAC 32/48/64, AES 16/32); либо точка не лежит на кривой; либо d ∉ [1,n-1]; либо формат не несжатый (0x04); либо приватный и открытый ключи не являются парой.

arrow_forwardЗаменить ключ

DAT_KEY_VERIFY_ONLY_UNSUPPORTEDКритичноПостоянно

Запрошен экспорт verify-only для семейства HMAC.

arrow_forwardСменить алгоритм

DAT_KEY_UNKNOWNЧастичноПостоянно

Ошибка ключа, не попавшая ни в одну из категорий выше.

arrow_forwardПроверить логи

Три похожих, но разных случая:

КодЗначение
DAT_KEY_VERIFY_ONLY_UNSUPPORTEDСтруктурное ограничение алгоритма. HMAC симметричен, понятия открытого ключа у него нет
DAT_SIG_KEY_MISSINGСостояние в рантайме. В этом ключе прямо сейчас нет приватной части
DAT_CERT_VERIFY_ONLYФорма развёртывания. Этот сертификат развёрнут только для проверки

Менеджер

Состояние объекта, который хранит сертификаты и использует их для выдачи и проверки.

DAT_MANAGER_NO_CERTIFICATEКритичноВременно

Нет ни одного сертификата. Либо импорт ещё не выполнялся, либо первая синхронизация с CMS не удалась.

arrow_forwardПроверить подключение к CMS

DAT_MANAGER_NO_ISSUABLE_CERTIFICATEКритичноПостоянно

Сертификаты есть, но ни один из них сейчас не пригоден для выдачи. Причина передаётся вместе с ошибкой.

arrow_forwardРешать по причине (cause) — таблица ниже

DAT_MANAGER_DISPOSEDКритичноПостоянно

Использован уже освобождённый менеджер или сертификат.

arrow_forwardИсправить вызывающий код

DAT_MANAGER_UNKNOWNЧастичноПостоянно

Ошибка менеджера, не попавшая ни в одну из категорий выше.

arrow_forwardПроверить логи

Причина (cause) у DAT_MANAGER_NO_ISSUABLE_CERTIFICATE — одна из четырёх. Для каждой причины нужны совершенно разные действия.

ПричинаЗначениеПовторЧто делать
DAT_CERT_NOT_YET_ISSUABLEДо начала окна выдачиВременноРазрешится само, если подождать
DAT_CERT_ISSUANCE_ENDEDОкно выдачи закрыто, доступна только проверкаПостоянноНужно развернуть новый сертификат
DAT_CERT_EXPIREDВсе имеющиеся истеклиПостоянноНужно обновить сертификаты
DAT_CERT_VERIFY_ONLYВсе имеющиеся — только для проверкиПостоянноОшибка настроек деплоя

Если сервер выдачи настроен получать только сертификаты для проверки, будет DAT_CERT_VERIFY_ONLY. Ожидание не поможет никогда, поэтому повторять не нужно.


Конфигурация

Проблемы значений, переданных вызывающей стороной. Все коды семейства CONFIGошибки, требующие правки кода; если они возникают в проде, значит деплой сделан неверно.

DAT_CONFIG_ALG_UNSUPPORTEDКритичноПостоянно

Неизвестное имя алгоритма. Должно точно совпадать с записью в формате протокола (ECDSA-P256, IV-AES256-GCM).

arrow_forwardПроверить имя алгоритма

DAT_CONFIG_ARGUMENT_INVALIDКритичноПостоянно

Обязательный аргумент равен null; либо вне допустимого диапазона (отрицательное время, interval <= 0); либо неподдерживаемый тип (в языках с динамической типизацией в payload передано число или булево); либо подписываемое тело пусто.

arrow_forwardИсправить вызывающий код

DAT_CONFIG_URI_INVALIDКритичноПостоянно

URI сервера CMS не соответствует спецификации: не разбирается, схема не http/https, либо присутствуют путь или query.

arrow_forwardИсправить URI

DAT_CONFIG_UNKNOWNКритичноПостоянно

Ошибка конфигурации, не попавшая ни в одну из категорий выше.

arrow_forwardПроверить логи


Внутренние

Проблемы среды исполнения и рантайма.

DAT_INTERNAL_UNAVAILABLEКритичноПостоянно

Криптографического бэкенда или API рантайма нет вовсе. Отсутствует crypto.subtle, платформа без поддержки AES-GCM, версия рантайма ниже требуемой.

arrow_forwardПроверить деплой и платформу

DAT_INTERNAL_UNKNOWNКритичноПостоянно

Сбой выделения памяти, сбой генерации случайных чисел, сбой захвата блокировки, попадание в ветку, спроектированную как недостижимая.

arrow_forwardПроверить логи

DAT_INTERNAL_UNAVAILABLE решается исправлением среды развёртывания, а DAT_INTERNAL_UNKNOWN — обычно сбой рантайма либо баг библиотеки.


Синхронизация CMS

Если синхронизация CMS не используется, эти коды не появляются.

DAT_CMS_UNREACHABLEЧастичноВременно

Сбой DNS, отказ в соединении, сбой TLS, таймаут. Таймаут не имеет отдельного кода и включён сюда — потому что реакция та же самая.

arrow_forwardПовторить после backoff

DAT_CMS_UNAUTHORIZEDКритичноПостоянно401

Сервер ответил 401. Токена нет либо он неверный.

arrow_forwardПроверить настройку токена

DAT_CMS_FORBIDDENКритичноПостоянно403

Сервер ответил 403. Токен валиден, но прав на этот эндпоинт нет.

arrow_forwardПроверить уровень токена

DAT_CMS_ENDPOINT_NOT_FOUNDКритичноПостоянно404

Сервер ответил 404. URL неверный.

arrow_forwardПроверить настройку URL

DAT_CMS_SERVER_ERRORЧастичноВременно5xx

Сервер ответил 5xx.

arrow_forwardПовторить после backoff

DAT_CMS_HTTP_STATUSКритичноПостоянно

Ответ не 2xx и не подходит ни под один из случаев выше.

arrow_forwardПроверить код состояния

DAT_CMS_MALFORMEDКритичноПостоянно

В ответе нет строки версии; либо строка версии не чисто десятичная; либо она вышла за диапазон.

arrow_forwardПроверить версию сервера

DAT_CMS_IMPORT_FAILEDКритичноПостоянно

Ответ получен, но применить сертификаты не удалось. Причина содержится в cause.

arrow_forwardПроверить CERT_* / KEY_* в cause

DAT_CMS_VERSION_RESETБез влиянияСостояние200

Сервер вернул версию более раннюю, чем наша. Это указание на полную повторную синхронизацию.

arrow_forwardОбрабатывается автоматически

DAT_CMS_NOT_SYNCEDКритичноВременно

Состояние, в котором синхронизация ещё ни разу не прошла успешно.

arrow_forwardДождаться первой синхронизации

DAT_CMS_SYNC_IN_PROGRESSБез влиянияСостояние

Предыдущая синхронизация ещё выполняется, поэтому текущий цикл пропущен. Это не ошибка.

DAT_CMS_NOT_SUPPORTEDКритичноПостоянно

Функциональность CMS не включена в сборку. Не активирован feature либо не подключён CURL.

arrow_forwardПроверить опции сборки

DAT_CMS_UNKNOWNЧастичноПостоянно

Ошибка CMS, не попавшая ни в одну из категорий выше.

arrow_forwardПроверить логи

Коды, при которых синхронизация признаётся окончательно провалившейся (UNAUTHORIZED, FORBIDDEN, ENDPOINT_NOT_FOUND, MALFORMED, IMPORT_FAILED), все критичны. Повтор их не решает, а сертификаты продолжают истекать, поэтому без вмешательства сервис неизбежно остановится.

Напротив, UNREACHABLE и SERVER_ERROR — частичные. Работа продолжается на прежних сертификатах, и в следующем цикле всё восстанавливается само. Но при непрерывных сбоях это в итоге переходит в критичное. Настраивайте алерт по числу подряд идущих неудач.

Сбой синхронизации не выбрасывается исключением

Даже если первая синхронизация провалилась, менеджер возвращается штатно — потому что лучше синхронизироваться позже, чем никогда. Вместо этого сбой остаётся доступным для запроса состоянием.

КлиентКак получить
Rustmanager.last_error().await
Gomanager.LastError()
JavaScriptmanager.lastError()
Pythonmanager.last_error()
Rubymanager.last_error
Java/Kotlinmanager.lastError
C#manager.LastError
C/C++dat_cms_manager_last_error(m)

Если успеха не было ни разу — DAT_CMS_NOT_SYNCED, при нормальной работе — пусто.


Сервер

Коды, которые выдаёт сервер CMS. Клиент эти коды не создаёт, а только принимает.

DAT_AUTH_UNAUTHORIZEDБез влиянияПостоянноshieldПодозрение401

Отсутствует заголовок Authorization, либо токен не зарегистрирован ни на одном уровне.

DAT_AUTH_FORBIDDENБез влиянияПостоянноshieldПодозрение403

Токен зарегистрирован, но его уровень не соответствует требуемому для этого эндпоинта.

DAT_AUTH_DISABLEDКритичноСостояние

Не настроен ни один токен, поэтому аутентификация отключена целиком. Открытым без аутентификации оказывается даже API выдачи сертификатов. В ответах не появляется, пишется только в лог запуска.

arrow_forwardНемедленно настроить токен

DAT_REQ_MALFORMEDБез влиянияПостоянноshieldПодозрение400

Не удаётся разобрать параметры пути или query, либо аргумент вне допустимого диапазона (отрицательный delay, срок более 10 лет и т. п.).

DAT_REQ_ALG_UNSUPPORTEDБез влиянияПостоянно400

Имя алгоритма в пути запроса неизвестно.

DAT_REQ_NOT_FOUNDБез влиянияПостоянноshieldПодозрение404·405

Такого маршрута нет либо метод не тот.

DAT_REQ_TOO_LARGEБез влиянияПостоянноshieldПодозрение413

Превышен размер тела запроса.

DAT_REQ_UNKNOWNБез влиянияПостоянно400

Ошибка запроса, не попавшая ни в одну из категорий выше.

DAT_STORE_UNAVAILABLEЧастичноВременно503

Обрыв соединения с БД, исчерпание пула соединений, конкуренция за блокировку, таймаут. Единственный код, использующий 503 — это сигнал, по которому клиент понимает: «здесь достаточно подождать».

arrow_forwardПовторить после backoff

DAT_STORE_UNKNOWNКритичноПостоянно500

Сбой чтения или записи, отсутствие таблицы, несоответствие схемы, повреждение сохранённой строки сертификата.

arrow_forwardПроверить состояние БД

Конверт ответа:

json
{
  "code": "DAT_REQ_ALG_UNSUPPORTED",
  "details": { "algorithm": "BOGUS-ALG" }
}

Ошибки, возникающие при создании и обработке сертификатов, сервер отдаёт теми же общими кодами, что описаны выше (DAT_CERT_*, DAT_KEY_*, DAT_CONFIG_*).

Когда приходит код сервера

Клиент оборачивает код сервера в собственный код CMS, а оригинал сохраняет в cause.

Что полученоHTTPКод, который выдаёт клиент
DAT_AUTH_UNAUTHORIZED401DAT_CMS_UNAUTHORIZED
DAT_AUTH_FORBIDDEN403DAT_CMS_FORBIDDEN
DAT_REQ_NOT_FOUND404DAT_CMS_ENDPOINT_NOT_FOUND
DAT_REQ_* (остальные)400·405·413DAT_CMS_HTTP_STATUS
DAT_STORE_UNAVAILABLE503DAT_CMS_SERVER_ERROR
DAT_STORE_UNKNOWN500DAT_CMS_SERVER_ERROR
(понижение версии)200DAT_CMS_VERSION_RESET

Поиск по симптомам

СимптомКод
Сразу после входа работает, а через некоторое время отказDAT_TOKEN_EXPIRED — срок жизни токена истёк. Достаточно перевыпустить
Проверка падает только на отдельных серверахDAT_CERT_NOT_SYNCED — этот сервер ещё не получил новый CID
Один и тот же токен отвергают все серверыDAT_CERT_NOT_FOUND — это CID, который мы никогда не выпускали
Сервер выдачи не может создать токенDAT_MANAGER_NO_ISSUABLE_CERTIFICATE + DAT_CERT_VERIFY_ONLYразвёрнут вариант verify-only
Выдача падает только сразу после запускаDAT_MANAGER_NO_CERTIFICATE — это до первой синхронизации. Скоро разрешится
Синхронизация CMS постоянно падаетDAT_CMS_UNAUTHORIZED — токен неверный. Повторы не помогут
Не приходит ни одного сертификатаDAT_CMS_ENDPOINT_NOT_FOUND — опечатка в URL
Падает только на конкретной платформеDAT_INTERNAL_UNAVAILABLE — нет криптографического бэкенда
Резко выросло число неудачных проверокDAT_SIG_MISMATCH — единичный случай безвреден, но лавина означает попытку подделки
Расшифровка secure внезапно перестала работатьDAT_CRYPTO_TAG_MISMATCH — разошлись сертификаты либо попытка подмены
Предупреждение в логе запуска CMSDAT_AUTH_DISABLEDаутентификация выключена. API выдачи открыт

Приложение

Синтаксис кода

DAT_<область>_<причина>
  • Если одна и та же причина возникает в разных областях, имя причины совпадает. DAT_TOKEN_MALFORMED и DAT_CERT_MALFORMED отличаются только объектом, смысл у них один.
  • _UNKNOWNтолько запасной вариант для своей области. Он не используется в значении «неизвестный алгоритм» (для этого есть _UNSUPPORTED).
  • Строка кода — это публичный контракт. Сообщение можно менять свободно, код — нет.
КатегорияПрефикс кода
ТокенDAT_TOKEN_
СертификатDAT_CERT_
ПодписьDAT_SIG_
ШифрованиеDAT_CRYPTO_
КлючDAT_KEY_
МенеджерDAT_MANAGER_
КонфигурацияDAT_CONFIG_
ВнутренниеDAT_INTERNAL_
Синхронизация CMSDAT_CMS_
СерверDAT_AUTH_ · DAT_REQ_ · DAT_STORE_

Доступ по клиентам

КлиентТип ошибкиКодКласс повтораСобытие безопасности
RustDatError enumerr.code()err.retry()err.security_event()
Go*dat.Errorerr.Codedat.Retry(err)dat.SecurityEvent(err)
JavaScriptDatError extends Errore.codee.retrye.securityEvent
PythonDatError(ValueError, RuntimeError)e.codee.retrye.security_event
RubySaro::Dat::Errore.codee.retrye.security_event?
Java/KotlinDatExceptione.codee.retrye.securityEvent
C#DatExceptione.Codee.Retrye.SecurityEvent
C/C++dat_error_tdat_error_code(e)dat_error_retry(e)dat_error_is_security_event(e)
Сервер CMSJSON-конвертполе code

Событие безопасности возвращает true только для двух кодов, где подделка или подмена установлены точно (DAT_SIG_MISMATCH, DAT_CRYPTO_TAG_MISMATCH). Метка подозрение в этом документе охватывает более широкий круг (включая подделанные токены, ключи и запросы) и пока является лишь документной классификацией, не выведенной в API клиентов.

Класс влияния — тоже документная классификация. Один и тот же код бьёт по-разному в зависимости от места возникновения: например, DAT_KEY_INVALID не влияет ни на что при фильтрации входящего токена, но при чтении сертификата во время синхронизации CMS обрушивает всю синхронизацию.

Первопричина не теряется. DAT_MANAGER_NO_ISSUABLE_CERTIFICATE и DAT_CMS_IMPORT_FAILED передают причину через цепочку исключений соответствующего языка (cause / __cause__ / InnerException / Unwrap()).

В C/C++ сохраняются и числовые значения

Прежние числовые значения dat_error_t оставлены ради совместимости ABI, но эталоном является строковый код. Библиотека больше не возвращает старые значения, поэтому сравнение вида err == DAT_ERROR_INVALID_DAT не сработает. Сверяйтесь через dat_error_code(e).

В C нет цепочек исключений, поэтому причина запрашивается отдельно через dat_manager_issuable_cause().