Интеграция с государственной системой маркировки «Честный Знак» (ГИС МТ) — это сложный процесс, требующий филигранной работы с криптографическими алгоритмами. Часто разработчики сталкиваются с ситуацией, когда авторизация и получение сессионного токена проходят успешно, но при попытке подписать и отправить входящие документы (например, УПД или титулы покупателя) сервер возвращает критическую ошибку: «Подпись не прошла проверку в crypto». В этой статье мы подробно разберем причины возникновения этой проблемы и рассмотрим проверенные способы ее решения с использованием как COM-объектов, так и встроенных средств платформы 1С. В качестве альтернативы ручному написанию кода можно применить готовое программное обеспечение для автоматизации работы с ЭЦП и кодами маркировки.
Первое, на что стоит обратить внимание — это различие в требованиях к подписи для разных методов API. Для получения ключа сессии (/api/v1/session) система обычно требует присоединенную подпись. Однако для работы с документами (например, через методы /api/v1/incoming-documents/xml/upd/title) требуется строго открепленная (detached) подпись в формате CAdES-BES.
Проанализируем ключевые моменты: если вы используете одну и ту же функцию для обоих случаев, скорее всего, ошибка кроется в неверном параметре bDetached. Рассмотрим, как это реализовать правильно.
Этот метод является классическим для интеграции с КриптоПро. Рассмотрим доработанную функцию, которая исключает лишние атрибуты, часто мешающие проверке на стороне «Честного Знака». Выясним причину: часто штамп времени (Signing Time) вызывает конфликты, если время на сервере 1С и сервере Честного Знака рассинхронизировано даже на несколько секунд.
Функция ПодписатьТекстCAdES(ТекстДляПодписи, ОтпечатокСертификата, ЭтоОткрепленнаяПодпись)
// Константы для работы с CAdESCOM
CADESCOM_BASE64_TO_BINARY = 1;
CADESCOM_CADES_TYPE_BES = 1;
CAPICOM_ENCODE_BASE64 = 0;
// Инициализируем объекты
Попытка
oSigner = Новый COMОбъект("CAdESCOM.CPSigner");
oSignedData = Новый COMОбъект("CAdESCOM.CadesSignedData");
Исключение
ЗаписьЖурналаРегистрации("Криптография", УровеньЖурналаРегистрации.Ошибка, , , "Библиотека CAdESCOM не установлена.");
Возврат Неопределено;
КонецПопытки;
// Получаем сертификат (реализация функции поиска по отпечатку приведена ниже)
oSigner.Certificate = ПолучитьСертификатПоОтпечатку(ОтпечатокСертификата);
// Важно: для Честного Знака часто лучше не добавлять атрибут времени вручную,
// если система этого не требует явно, так как формат BES подразумевает его наличие внутри.
// Если нужно добавить, используем oSigner.AuthenticatedAttributes2.Add(oSigningTimeAttr);
oSignedData.ContentEncoding = CADESCOM_BASE64_TO_BINARY;
oSignedData.Content = ТекстДляПодписи; // Текст должен быть в Base64
Попытка
// Основной метод подписания
РезультатПодписи = oSignedData.SignCades(oSigner, CADESCOM_CADES_TYPE_BES, ЭтоОткрепленнаяПодпись, CAPICOM_ENCODE_BASE64);
// Очищаем результат от символов переноса строк, которые добавляет COM-объект
РезультатПодписи = СтрЗаменить(РезультатПодписи, Символы.ПС, "");
РезультатПодписи = СтрЗаменить(РезультатПодписи, Символы.ВК, "");
Возврат РезультатПодписи;
Исключение
Сообщить("Ошибка при формировании подписи: " + ОписаниеОшибки());
Возврат "";
КонецПопытки;
КонецФункции
Начиная с современных версий платформы 8.3, рекомендуется использовать объект МенеджерКриптографии. Это позволяет избежать проблем с регистрацией COM-компонентов и повышает стабильность системы. Посмотрим на пример реализации открепленной подписи для документов маркировки:
Функция ПодписатьДанныеЧерезМенеджер(ДанныеДляПодписи, Отпечаток)
// Инициализируем менеджер с указанием провайдера ГОСТ 2012
// Имя провайдера может отличаться в зависимости от установленной версии КриптоПро
ИмяПровайдера = "Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider";
ТипПровайдера = 80;
Менеджер = Новый МенеджерКриптографии(ИмяПровайдера, "", ТипПровайдера);
// Ищем сертификат в личном хранилище
Хранилище = Менеджер.ПолучитьХранилищеСертификатов(ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты);
ДвоичныйОтпечаток = ПолучитьДвоичныеДанныеИзHexСтроки(Отпечаток);
МассивСертификатов = Хранилище.НайтиПоОтпечатку(ДвоичныйОтпечаток);
Если МассивСертификатов.Количество() = 0 Тогда
ВызватьИсключение "Сертификат с указанным отпечатком не найден!";
КонецЕсли;
Сертификат = МассивСертификатов[0];
// Для ГИС МТ данные должны быть переданы как ДвоичныеДанные
Если ТипЗнч(ДанныеДляПодписи) = Тип("Строка") Тогда
// Обязательно используем UTF-8 БЕЗ BOM
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(ДанныеДляПодписи, КодировкаТекста.UTF8, Ложь);
Иначе
ДвоичныеДанные = ДанныеДляПодписи;
КонецЕсли;
// Формируем открепленную подпись
// Метод Подписать(Данные, Сертификат) создает отсоединенную подпись в формате CMS (PKCS#7)
ДД_Подписи = Менеджер.Подписать(ДвоичныеДанные, Сертификат);
// Кодируем в Base64 и удаляем лишние символы
СтрокаПодписи = Base64Строка(ДД_Подписи);
СтрокаПодписи = СтрЗаменить(СтрокаПодписи, Символы.ПС, "");
СтрокаПодписи = СтрЗаменить(СтрокаПодписи, Символы.ВК, "");
Возврат СтрокаПодписи;
КонецФункции
Даже если ваш код технически верен, проверка «Честного Знака» может отклонить подпись из-за мельчайших неточностей в подготовке данных. Рассмотрим основные «подводные камни»:
BOM (Byte Order Mark), хэш файла будет рассчитан неверно. В 1С при использовании ЗаписьТекста или ПолучитьДвоичныеДанныеИзСтроки всегда указывайте параметр использования BOM как Ложь.Base64Строка() в 1С или COM-объекты могут вставлять символы CRLF (перенос строки) каждые 64 или 72 символа. Их обязательно нужно удалять с помощью СтрЗаменить.CadesSignedData свойство ContentEncoding должно быть установлено в 1 (CADESCOM_BASE64_TO_BINARY), если вы передаете в Content уже закодированную строку. Однако надежнее передавать чистые двоичные данные, если платформа это позволяет.Если ошибка сохраняется, проанализируем ситуацию методом исключения. Воспользуйтесь следующей инструкцией:
1. Сохраните XML-файл, который вы пытаетесь отправить, на диск в кодировке UTF-8.
2. Подпишите его с помощью утилиты КриптоПро CSP (cryptcp) или через браузерный плагин на официальном сайте КриптоПро (в разделе проверки подписи).
3. Сравните полученную строку Base64 с той, которую генерирует ваш код в 1С. Если строки различаются в начале — ищите проблему в заголовках (атрибутах) подписи. Если они различаются полностью — проблема в исходных данных (кодировка или невидимые символы).
Использование Менеджера Криптографии с правильным указанием провайдера 80 (для ГОСТ 2012) обычно решает большинство проблем, так как 1С автоматически корректно обрабатывает низкоуровневые вызовы API криптопровайдера. Помните, что для успешной интеграции с Честным Знаком важно соблюдать последовательность: Подготовка данных (UTF-8 без BOM) -> Подписание (CAdES-BES, Detached) -> Очистка Base64 от переносов -> Отправка в POST-запросе. Если в процессе настройки обмена возникают и другие сложности, можно использовать практический сборник готовых решений по интеграции 1С с ГИС МТ.