Ситуация из реального разбора. Работало подключение к Честному ЗНАКу: программа подписывала документы УКЭП и отправляла через True API. Пришёл плановый перевыпуск подписи — и всё встало. Симптомы на выбор, у кого какой:
- «Cannot find User certificate» — хотя сертификат в хранилище виден;
- подпись проходит, но ГИС МТ отвечает 401 «unknown key»;
- документ уходит, статус «ошибка проверки подписи» (403);
- программа просто зависает на этапе подписания.
Ниже — почему это происходит у всех примерно раз в год, как диагностировать за пять минут и как написать выбор сертификата так, чтобы следующий перевыпуск прошёл незаметно.
Корень: после перевыпуска сертификатов ДВА
Удостоверяющий центр выпускает новый сертификат, но старый из хранилища никуда не девается. Он лежит рядом: тот же владелец, тот же ИНН, часто тот же CN. Разница — в сроке действия и отпечатке.
А теперь главный вопрос: как ваша программа выбирает сертификат для подписи?
Варианты, которые я встречал в живом коде и настройках:
- По ИНН — находит ДВА, берёт первый попавшийся. Какой «первый» — зависит от порядка в хранилище, то есть от фазы луны.
- По имени владельца (CN) — та же лотерея.
- «Первый действующий» — уже теплее, но старый сертификат в день перевыпуска ещё действует: перекрытие сроков обычно недели.
- По отпечатку (thumbprint) — единственный однозначный способ. Но отпечаток нового сертификата другой, а в настройках зашит старый.
Отсюда и вилка симптомов. Если выбор «по ИНН» — программа случайно берёт то старый, то новый: подпись валидна, но ГИС МТ ждёт ключ, привязанный к кабинету, и отвечает 401/403. Если в настройках жёсткий отпечаток старого — после его окончания «Cannot find User certificate».
Диагностика за пять минут, без установки чего-либо
Всё делается штатным csptest из состава КриптоПро CSP.
Список сертификатов в хранилище пользователя:
csptest -keyset -enum_cont -verifycontext -fqcn
Смотрим на контейнеры. Дальше — сертификаты с датами и отпечатками через certmgr КриптоПро:
certmgr -list -store uMy
В выводе по каждому сертификату: Subject (владелец), Serial, SHA1 Thumbprint, Not valid before/after. Ищете два сертификата с одним ИНН — и сразу видно, какой истекает, а какой новый.
Пробная подпись конкретным сертификатом (по отпечатку):
csptest -sfsign -sign -in test.txt -out test.sig -my <SHA1-отпечаток>
Если подпись прошла старым, а ГИС МТ отвечает 401 — вы нашли причину: система подписывает живым, но НЕ ТЕМ ключом.
Почему ГИС МТ отвечает 401, хотя подпись валидна
True API авторизует не «любую валидную УКЭП», а конкретный ключ, которым подтверждён вход участника. Схема авторизации:
- GET /auth/key — получаем uuid и случайные данные;
- подписываем данные УКЭП (отсоединённая подпись);
- POST /auth/simpleSignIn — отправляем подпись, получаем токен на 10 часов.
Если на шаге 2 подпись сделана новым сертификатом, а кабинет участника ещё не знает о нём — 401. Если старым, который уже отозван — 403 на проверке. Лечится в кабинете ЧЗ: профиль → пользователи → обновить сертификат (новый подтягивается после первого входа по нему через плагин).
Отдельная ловушка входа в кабинет: расширение КриптоПро в браузере после обновления Chrome отваливается, и «не могу войти в ЛК» накладывается на «программа не подписывает» — два разных инцидента выглядят как один. Держите запасной браузер с работающим плагином.
Карта симптомов: что видите — где копать
Симптомы одного корня маскируются под разные поломки. Сверьтесь до того, как переустанавливать КриптоПро (спойлер: переустановка не лечит ни один пункт):
| Симптом | Что на самом деле | Куда смотреть |
|---|---|---|
| «Cannot find User certificate» | в настройках отпечаток старого серта, он истёк или удалён | certmgr -list, сверить отпечаток из настроек с живыми |
| 401 unknown key от True API | подпись валидна, но ключ не привязан к кабинету | кем подписали (csptest), вход в ЛК новым сертом |
| 403 на проверке подписи | подписали отозванным/истёкшим | даты в certmgr, отозванность |
| Программа зависает на подписании | pin-код токена ждёт ввода в невидимом окне | подпись из-под того же пользователя, кэширование pin |
| Работает через раз | выбор «по ИНН» находит два серта, берёт случайный | логика выбора в коде/настройке |
| После обновления Chrome не войти в ЛК | отвалился плагин КриптоПро в браузере | второй браузер, переустановка расширения |
Отдельно про зависание: если служба или фоновое задание подписывает из-под другого пользователя Windows, диалог pin-кода Рутокена открывается в чужой сессии — для вас это выглядит как вечное зависание без ошибки. Лечится кэшированием pin в панели КриптоПро или переносом подписания в сессию пользователя.
Почему это ломается «у всех и раз в год»
Перевыпуск УКЭП — плановое событие: срок сертификата 12–15 месяцев. То есть инцидент встроен в календарь. При этом:
- настраивает подключение обычно интегратор при внедрении — и уходит;
- через год перевыпуск делает бухгалтер по инструкции УЦ, в которой про учётную систему нет ни слова;
- падает всё в день отгрузки, потому что документы в ГИС МТ вспоминают, когда они не ушли.
Три разных человека, три зоны ответственности, ноль передачи знания. Поэтому самое ценное в закрытии инцидента — не «починил», а инструкция на следующий раз, привязанная к месту, где её найдут: прямо в настройках программы рядом с полем отпечатка.
Как написать выбор сертификата правильно
Правило одно: в настройках храните SHA1-отпечаток, выбор — только по нему. Плюс два защитных слоя:
- Проверка срока при старте. За 30 дней до Not valid after — предупреждение в лог и на экран. Перевыпуск перестаёт быть сюрпризом.
- Процедура смены отпечатка. После перевыпуска надо сделать ровно два действия: обновить отпечаток в настройках и один раз войти новым сертификатом в кабинет ЧЗ. Запишите это в инструкцию оператору — обе операции по минуте.
Псевдокод выбора (одинаково ложится на 1С и на любой другой стек):
серт = НайтиПоОтпечатку(НастройкаОтпечаток)
Если серт = Неопределено Тогда
Ошибка("Сертификат с отпечатком ... не найден. После перевыпуска
обновите отпечаток: инструкция п.4")
Если серт.ДействителенДо < ТекущаяДата + 30 дней Тогда
Предупреждение("Сертификат истекает " + серт.ДействителенДо)
Никаких «по ИНН», никаких «первый действующий». Однозначность дешевле любой эвристики: эвристика и создала этот инцидент.
Скрипт-диагност: собрать картину одним запуском
Чтобы не гонять команды по одной, соберите их в диагностический скрипт — он ничего не меняет, только читает и складывает отчёт в файл. Скелет на PowerShell (пути КриптоПро типовые):
$отчёт = "diag-chz-$(Get-Date -Format 'yyyy-MM-dd-HHmm').txt"
$cpdir = "$env:ProgramFiles\Crypto Pro\CSP"
"=== Сертификаты uMy ===" | Out-File $отчёт
& "$cpdir\certmgr.exe" -list -store uMy | Out-File $отчёт -Append
"=== Контейнеры ===" | Out-File $отчёт -Append
& "$cpdir\csptest.exe" -keyset -enum_cont -verifycontext -fqcn |
Out-File $отчёт -Append
"=== Пробная подпись по отпечатку из настроек ===" | Out-File $отчёт -Append
"тест" | Out-File test-sign.txt
& "$cpdir\csptest.exe" -sfsign -sign -in test-sign.txt -out test-sign.sig `
-my ВАШ_ОТПЕЧАТОК_ИЗ_НАСТРОЕК 2>&1 | Out-File $отчёт -Append
Что даёт: один файл, в котором видно все сертификаты с датами и отпечатками, все контейнеры и результат подписи именно тем ключом, который прописан в системе. С таким отчётом причина инцидента находится за минуты — и его же можно приложить в поддержку, если проблема окажется на стороне оператора ЭДО или УЦ.
Два предостережения. Первое: скрипт запускается из-под того пользователя, под которым работает подписание — сертификаты в uMy у каждого свои. Второе: pin-код скрипт не спрашивает и нигде не сохраняет; если подпись просит pin — это уже само по себе диагноз (см. строку про зависание в карте симптомов).
Чек-лист после каждого перевыпуска УКЭП
- certmgr -list — увидеть оба сертификата, выписать новый отпечаток.
- Обновить отпечаток в настройках всех систем, которые подписывают (учётная система, обработка обмена, сервис заказа кодов — их может быть больше одной!).
- Войти в кабинет ЧЗ новым сертификатом через браузер с плагином.
- Пробная подпись csptest по новому отпечатку.
- Пробный вызов True API: auth/key → simpleSignIn → получен токен.
- Старый сертификат НЕ удалять до конца перекрытия сроков: им могут быть подписаны неотправленные документы.
Ещё три вопроса из практики
«А можно просто удалить старый сертификат?» Можно — и получить отказ проверки на документах, подписанных им до перевыпуска, если их придётся переотправлять. Старый ключ живёт до конца перекрытия сроков, удаление — после.
«У нас облачная 1С/сервис — нам это не грозит?» Грозит точно так же: меняется только место, где лежит отпечаток. В облачных сценариях добавляется задержка поддержки провайдера — закладывайте её в план перевыпуска.
«Токен один, а рабочих мест три». Значит, перевыпуск ломает три места одновременно, и чек-лист выполняется на каждом. Держите список всех точек, где живёт подписание — при разборе таких инцидентов обычно находится точка, про которую забыли (чаще всего — сервис заказа кодов у упаковщика).
Итог
Инцидент «после перевыпуска всё сломалось» — не про КриптоПро и не про ГИС МТ. Он про выбор сертификата по неоднозначному признаку. Дыра закладывается в день настройки, а срабатывает через год, когда рядом с рабочим ключом появляется его близнец. Отпечаток в настройках, проверка срока на старте и две строчки инструкции оператору — и следующий перевыпуск пройдёт за пять минут, а не за день простоя отгрузок.
И последнее. Если инцидент уже случился и отгрузки стоят — не начинайте с переустановки КриптоПро. Начните с certmgr -list: в девяти случаях из десяти ответ лежит в первых двадцати строках вывода — два сертификата с одним ИНН и неверный отпечаток в настройках. Полчаса на диагностику по этой статье против дня на «переустановим всё» — обычная цена вопроса.
Вступайте в нашу телеграмм-группу Инфостарт