Осуществляет поиск сертификатов в хранилище по заданному отпечатку. Для работы метода на веб-клиенте необходимо предварительно подключить расширение работы с криптографией. В веб-клиенте метод поддерживается только в браузере Internet Explorer, если в конфигурации используется режим синхронных вызовов расширений платформы и внешних компонент.
Синтаксис
НайтиПоОтпечатку(<Отпечаток>)Полное описание, параметры и ограничения
ХранилищеСертификатовКриптографии.НайтиПоОтпечатку (CryptoCertificateStore.FindByThumbprint)
ХранилищеСертификатовКриптографии (CryptoCertificateStore)
НайтиПоОтпечатку (FindByThumbprint)
Доступен, начиная с версии 8.2.
Синтаксис:
НайтиПоОтпечатку(<Отпечаток>)
Параметры:
<Отпечаток> (обязательный)
Тип: ДвоичныеДанные.
Отпечаток, по которому производится поиск.
Возвращаемое значение:
Тип: Неопределено, СертификатКриптографии.
Неопределено - сертификат не найден.
Описание:
Осуществляет поиск сертификатов в хранилище по заданному отпечатку.
Для работы метода на веб-клиенте необходимо предварительно подключить расширение работы с криптографией. В веб-клиенте метод поддерживается только в браузере Internet Explorer, если в конфигурации используется режим синхронных вызовов расширений платформы и внешних компонент.
Доступность:
Тонкий клиент, веб-клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер.
См. также:
ХранилищеСертификатовКриптографии, метод НачатьПоискПоОтпечатку
ХранилищеСертификатовКриптографии, метод НайтиПоОтпечаткуАсинх
Использование в версии:
Доступен, начиная с версии 8.2.
Описание изменено в версии 8.3.24.
Методическая информация
Практические примеры
Найти точный двоичный отпечаток синхронно
Отпечаток берётся из разобранного собственного DER, не из строки с пробелами. Синхронный/callback результат одиночный; обещание в установленной справке описано как массив. Полный модуль читает только выбранную область и показывает исключительно наш публичный учебный образец.
Где и как запускать
Полный модуль управляемой формы; своя отдельная Windows-учётная запись и пустая учебная конфигурация на 8.5.1.1343. Поиск своего публичного DER в Личном текущего пользователя ОС. Здесь в 1С не запускался.
Подготовка
Используйте свою отдельную пустую конфигурацию УчебнаяКонфигурацияСинтаксиса и Windows-клиент ровно 8.5.1.1343. Рабочие базы и служебные учётные записи сервера исключены.
Для опыта с системным хранилищем войдите в отдельную собственную учебную учётную запись Windows без рабочих сертификатов. Хранилище не принадлежит базе 1С: оно принадлежит текущему пользователю ОС.
Создайте свою обработку с управляемой формой: Занято — Булево, начально Ложь; ПодтверждаюОтдельныйСтенд — Булево, начально Ложь; Отчёт — Строка длиной 0, многострочное поле только для просмотра.
Создайте команду НайтиУчебныйСертификат и свяжите с одноимённым клиентским обработчиком. Вставьте полный модуль одного урока, включая общие функции и экспортные callback.
Перед запуском вручную убедитесь, что вошли именно в свой отдельный Windows-стенд, затем отметьте ПодтверждаюОтдельныйСтенд. Флажок — подтверждение оператора, а не автоматическая проверка личности Windows-пользователя.
В код встроен публичный DER-сертификат Syntax Guide Training Only. Закрытого ключа в нём нет; он не доверенный и не был установлен при подготовке этих уроков.
Первый опыт выполняйте без установки образца: корректный результат — ноль найденных учебных сертификатов. Код не создаёт отсутствующий сертификат в хранилище и не объявляет пустой результат ошибкой криптографии.
Для положительного опыта администратор вашего отдельного стенда может заранее вручную разместить только этот публичный CER-образец в Личное текущей учебной учётной записи. Не помещайте его в Доверенные корневые и не используйте рабочий PFX. Эти примеры не выполняют импорт.
Microsoft Enhanced RSA and AES Cryptographic Provider и числовой тип 24 подтверждены в установленной Windows-регистрации. Если он отсутствует на своём стенде, остановитесь; нельзя угадывать имя, тип или путь библиотеки.
Открывается только ПерсональныеСертификаты + ДанныеПользователяОС. Это не хранилище локального компьютера, не корневое и не мобильное ДанныеПриложения. Другие области не открываются автоматически при пустом результате.
Субъект и издатель в поиске сопоставляются по содержащейся строке, поэтому окончательная принадлежность образцу проверяется по точному отпечатку DER. Название CN само по себе недостаточно.
Весь отчёт остаётся в форме. Нет подписи, PIN, закрытого ключа, файла, HTTP, OCSP/CRL, установки расширения, Добавить/Удалить или изменения доверия ОС.
Синхронный вариант требует разрешённого режима синхронных вызовов. В варианте Ждать весь обработчик Асинх; в callback-цепочке результат возникает только после трёх этапов.
При подготовке хранилище не открывалось и код в 1С не запускался. Сигнатуры и возвращаемые типы сверены с установленной справкой; runtime-проверка и доверие сертификату этим не подтверждаются.
&НаКлиенте
Процедура НайтиУчебныйСертификат(Команда)
Если Занято Тогда
Возврат;
КонецЕсли;
Занято = Истина;
Попытка
ПроверитьОтдельныйСтенд();
Образец = ПолучитьСвойПубличныйОбразец();
Менеджер = Новый МенеджерКриптографии("Microsoft Enhanced RSA and AES Cryptographic Provider", "", 24, ИспользованиеИнтерактивногоРежимаКриптографии.НеИспользовать);
Хранилище = Менеджер.ПолучитьХранилищеСертификатов(ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты, РасположениеХранилищаСертификатовКриптографии.ДанныеПользователяОС);
ПроверитьСвоёХранилище(Хранилище);
Результат = Хранилище.НайтиПоОтпечатку(Образец.Отпечаток);
Отчёт = СформироватьУчебныйПоиск(Результат, Образец, Ложь);
Исключение
Отчёт = "Учебный поиск не подтверждён. Проверьте свой стенд, провайдер и тип результата по справке; это не успешный поиск.";
КонецПопытки;
Занято = Ложь;
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьУчебнуюПлатформу()
Система = Новый СистемнаяИнформация;
Если Система.ТипПлатформы <> ТипПлатформы.Windows_x86
И Система.ТипПлатформы <> ТипПлатформы.Windows_x86_64 Тогда
ВызватьИсключение "Этот пример использует Windows CryptoAPI";
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьОтдельныйСтенд()
ПроверитьУчебнуюПлатформу();
Если НЕ ПодтверждаюОтдельныйСтенд Тогда
ВызватьИсключение "Сначала подтвердите свою отдельную учебную учётную запись Windows";
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьСвоёХранилище(Хранилище)
Если ТипЗнч(Хранилище) <> Тип("ХранилищеСертификатовКриптографии") Тогда
ВызватьИсключение "Ожидалось собственное хранилище заданной области";
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Функция ПолучитьСвойПубличныйОбразец()
Данные = Base64Значение("MIIC+jCCAeKgAwIBAgIBVTANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpTeW50YXggR3VpZGUgVHJhaW5pbmcgT25seTAeFw0yMDAxMDEwMDAwMDBaFw0zNTEyMzEwMDAwMDBaMCUxIzAhBgNVBAMMGlN5bnRheCBHdWlkZSBUcmFpbmluZyBPbmx5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkraGtF6mSMHQWI0lIdDxzNjLTB0VHmtLUYEIxXFFJepQtyMGWZ9rfpbTglFp8wpsw+Wc09FQyDFuKsNz3cBcBBx7fTmJVuYzfrXjhDECNqEoKMEf+Qrim3WsVKA/Qr8IMnzq1qdnA1pLgaaKyscfCJkw9W1yoTlLV3PmGs6h6gP1/KXwe+zKN5r3Jl0IVk8RXTLAeyqN01lCuyzaeSYm/v2YS88LdaJ/nkdFqy5QjRXfm7EOCW7eCZlCBwW0EvGhUarZxWlq04lPs9qu3aC3/6gY/scE2vY1jeZV2VpV0lLQpU5gVdjVGI4YQmfgkb8jYtV5U7FQ1KQ6Poji/ort6wIDAQABozUwMzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEARoo1FJJKKkaZXyFl1tlYj8K7xvryXwhb+tCaFvdXuON27YC3/YIHLUT9sCF9o76VIT8dsVMpK0Qo+VV0FIvqRcB+u6SmyJ+Y7590mzd5P1CSt8Y/4BNV2LosYxhcdVczs26PWHL5GXyBMWRxtBjNsnTeMKh4/WIMrplAr0IOJCmjIeKhv0JbQacsNqhmpe7JdgtBYC4Rrn3ajdD99HZREmyLR/iJrh6W4IGqSN0MGT0xL/mLI0GsTp9JhHDF3o8bmC1yMDlLOoAZp7M072bzfDsKFPg4ATQp/hhbtsTdS/LXrd9cLehZ7ThH6ljL8y2JbALD+6HPnT6Sv+Mg0Wq0MA==");
Образец = Новый СертификатКриптографии(Данные);
Если Base64Строка(Образец.Отпечаток) <> "tRDNiwoaiFssHhQqwyjWVlPLdns=" Тогда
ВызватьИсключение "Встроенный публичный образец не совпадает с ожидаемыми DER-данными";
КонецЕсли;
Возврат Образец;
КонецФункции
&НаКлиенте
Функция СформироватьУчебныйПоиск(Результат, Образец, ОжидаетсяМассив)
Если ОжидаетсяМассив Тогда
Если ТипЗнч(Результат) <> Тип("Массив") Тогда
ВызватьИсключение "Результат не соответствует массиву из установленной справки; требуется проверка этого метода в 1С";
КонецЕсли;
Кандидаты = Результат;
Иначе
Кандидаты = Новый Массив;
Если Результат <> Неопределено Тогда
Если ТипЗнч(Результат) <> Тип("СертификатКриптографии") Тогда
ВызватьИсключение "Поиск по отпечатку должен вернуть сертификат или Неопределено";
КонецЕсли;
Кандидаты.Добавить(Результат);
КонецЕсли;
КонецЕсли;
Строки = Новый Массив;
НайденоСвоих = 0;
Для Каждого НайденныйСертификат Из Кандидаты Цикл
Если ТипЗнч(НайденныйСертификат) <> Тип("СертификатКриптографии") Тогда
ВызватьИсключение "В результате поиска ожидался сертификат";
КонецЕсли;
Если Base64Строка(НайденныйСертификат.Отпечаток) <> Base64Строка(Образец.Отпечаток) Тогда
Продолжить;
КонецЕсли;
CN = Неопределено;
Если НЕ НайденныйСертификат.Субъект.Свойство("CN", CN) Тогда
ВызватьИсключение "В собственном образце не найден учебный CN";
КонецЕсли;
Если CN <> "Syntax Guide Training Only" Тогда
ВызватьИсключение "Учебный CN не совпал с собственным DER-образцом";
КонецЕсли;
НайденоСвоих = НайденоСвоих + 1;
Строки.Добавить("Только собственный учебный CN: " + CN);
Строки.Добавить("Серийный номер образца, Base64: " + Base64Строка(НайденныйСертификат.СерийныйНомер));
Строки.Добавить("Начало срока образца: " + Строка(НайденныйСертификат.ДатаНачала));
Строки.Добавить("Окончание срока образца: " + Строка(НайденныйСертификат.ДатаОкончания));
КонецЦикла;
Строки.Добавить("Точных учебных совпадений: " + Строка(НайденоСвоих));
Если НайденоСвоих = 0 Тогда
Строки.Добавить("В Личном текущего учебного пользователя ОС образец не найден. Это допустимый отрицательный опыт, а не доказательство отсутствия рабочих ключей.");
КонецЕсли;
Строки.Добавить("Ничего не импортировано и не подписано. Наличие образца в хранилище не подтверждает доверие.");
Возврат СтрСоединить(Строки, Символы.ПС);
КонецФункции
Разбор по шагам
Проверить собственную конфигурацию, Windows и явное подтверждение отдельного стенда до получения хранилища.
Разобрать встроенные публичные DER-байты и проверить ожидаемый отпечаток собственного образца. Это не импорт сертификата в ОС.
Инициализировать менеджер с настоящими именем провайдера и типом 24 в неинтерактивном режиме.
Получить хранилище конкретного типа и расположения, затем проверить тип возвращённого объекта. Не создавать его через Новый.
Выполнить только выбранный поиск, принять документированный тип результата и отфильтровать посторонние совпадения по точному отпечатку.
Показать только наш учебный CN, серийный номер, срок и число точных совпадений. Отсутствие образца обработать явно; повторный запуск блокировать флагом Занято.
Создать уже инициализированный менеджер и получить хранилище синхронно.
Выполнить НайтиПоОтпечатку только после проверки полученного хранилища.
Для sync/callback допускается Неопределено. Для Ждать установленная справка требует массив; иной тип явно отклоняется и должен быть исследован на своём стенде.
Как проверить результат
Без заранее установленного образца показано «Точных учебных совпадений: 0»; метод не импортирует недостающий сертификат.
В положительном опыте видны только Syntax Guide Training Only и сведения этого DER-образца; чужие совпадения не выводятся.
Пустой/неверный тип, ошибка и незавершённая асинхронная операция не объявляются успешным поиском.
Занято снят только после завершения/ошибки. В хранилище ничего не добавлено/удалено, корневое доверие не менялось.
Ожидаемый результат
В своей форме получен проверяемый положительный или отрицательный результат поиска публичного учебного образца, без закрытого ключа и без изменения системного хранилища.
На что обратить внимание
ХранилищеСертификатовКриптографии не имеет конструктора и не является коллекцией сертификатов в памяти вашей базы. Его получают у инициализированного МенеджерКриптографии.
Чтение текущего пользователя ОС не означает чтение пользователей 1С. Отдельная конфигурация сама по себе не отделяет рабочие сертификаты Windows: нужен отдельный собственный пользователь стенда.
НайтиПоСубъекту и поиск издателя проверяют вхождение строки, а не равенство CN или криптографическую принадлежность. Точный отпечаток проверяется до вывода полей.
НайтиПоОтпечатку и его callback возвращают сертификат либо Неопределено. У НайтиПоОтпечаткуАсинх установленная справка явно указывает массив: нельзя переносить тип результата из синхронного метода.
Если асинхронный отпечаток фактически вернёт тип, отличный от документированного массива, урок остановится с диагностикой несовпадения контракта, а не объявит успех. Это место требует отдельной проверки в 1С.
Пустая выборка означает отсутствие именно нашего публичного образца в выбранной области. Не следует из неё делать вывод, что у человека нет рабочего ключа или сертификата в другой области.
Найденный учебный сертификат не становится доверенным, пригодным для подписи или связанным с закрытым ключом только из-за нахождения в Личном.
Не подменяйте учебный отпечаток чужим. Отчёт не выводит субъект, издателя, серийный номер или даты непривязанного к образцу сертификата.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.
Асинхронно подписать свой PDF и получить реальные результаты проверки в тонком клиенте
Полный модуль собственной формы получает свои PDF-байты с сервера, использует явно подготовленный CurrentUser-ключ, ждёт подпись/запись/чтение и проверяет реальные Array/Certificate-результаты Promise. Ни Promise, ни выходные параметры синхронных overloads не подменяют готовый результат.
Где и как запускать
Полный модуль управляемой формы собственного тонкого Windows-клиента: PDF-операции с Ждать, отдельный полный supporting-серверный модуль для генерации своих байтов. В1С не запускался.
Подготовка
НОВАЯ пустая файловая учебная база УчебнаяАсинхроннаяПодписьPDF85 на8.5.1.1343, совместимость Не использовать. Только свои модуль и форма; без рабочих объектов, расширений, подписок/заданий. Запускать под ОТДЕЛЬНЫМ собственным Windows-пользователем или в отдельном учебном Windows-стенде без рабочих сертификатов. Не серверный кластер под служебной учётной записью.
Для будущей ручной подготовки отключите сеть учебного стенда. Все операции подписи локальны, TSA-массив в коде явно пуст. Команды создания ключа ниже НЕ выполнялись при подготовке справочника; они создают собственный сертификат и закрытый ключ в Личном текущего учебного Windows-пользователя.
Откройте Windows PowerShell в своём отдельном учебном профиле, не от администратора рабочего сервера. В одной и той же консоли вручную выполните последовательно только следующие четыре команды; не закрывайте её между командами. Провайдер Microsoft Enhanced RSA and AES Cryptographic Provider должен существовать и иметь Type24. CNG-провайдер по умолчанию не подставлять вместо него.
Ручная команда 1: $pdfTrainingId = [guid]::NewGuid().ToString("D")
Ручная команда 2: $pdfTrainingCert = New-SelfSignedCertificate -Type Custom -Subject ("CN=Syntax Guide PDF Own85 " + $pdfTrainingId) -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -KeySpec Signature -KeyAlgorithm RSA -KeyLength 2048 -KeyUsage DigitalSignature -HashAlgorithm SHA256 -KeyExportPolicy NonExportable -CertStoreLocation "Cert:\CurrentUser\My" -NotAfter (Get-Date).AddMonths(1)
Ручная команда 3: if (-not $pdfTrainingCert.HasPrivateKey) { throw "Own training private key was not created" }
Ручная команда 4: [pscustomobject]@{TrainingId=$pdfTrainingId;ThumbprintHex=$pdfTrainingCert.Thumbprint;OwnPrivateKey=$pdfTrainingCert.HasPrivateKey;Subject=$pdfTrainingCert.Subject}
Сохраните показанные TrainingId и ThumbprintHex для этой попытки. OwnPrivateKey должен быть True, Subject должен содержать только Syntax Guide PDF Own85 и ваш новый TrainingId. Ключ не экспортируется в PFX и не печатается. Сертификат самоподписанный и не добавляется в доверенные корневые.
Команды и различие legacy CSP/KeySpec=Signature сверены с официальной документацией Microsoft New-SelfSignedCertificate: https://learn.microsoft.com/en-us/powershell/module/pki/new-selfsignedcertificate?view=windowsserver2025-ps. Это документирование будущего учебного опыта, не выполненное создание ключа.
Учебный сертификат и ключ остаются в собственном Windows-профиле после закрытия1С; урок их автоматически не удаляет. Администратор отдельного стенда отвечает за его очистку после обучения. Не переносите опыт в рабочий профиль и не выдавайте закрытие формы за удаление ключа.
Ни PowerShell-команды, ни CryptoAPI/1С, ни AddSignature, ни GUI/сервер/ключи/подпись здесь не запускались. runtimeVerifiedScenarios=0.
Используйте именно тонкий Windows-клиент собственной файловой базы8.5.1.1343. В конфигурации разрешите синхронные вызовы расширений платформы/внешних компонент: сведения, инициализация CryptoAPI и поиск своего сертификата здесь синхронные. Асинхронны PDF-операции; это не обещание полностью неблокирующего криптографического стека.
Основной код теперь вставляется В МОДУЛЬ ФОРМЫ, не в серверный общий модуль. Своя управляемая форма: реквизиты МеткаСертификата85 Строка100, ОтпечатокHex85 Строка40, ПодтверждаюСвойСтенд Булево начально Ложь, Занято Булево начально Ложь, Отчёт Строка0. Поля с теми же путями; Занято не редактировать, Отчёт многострочный ТолькоПросмотр=Да. Команда/кнопка Выполнить, действие Выполнить. Вставьте весь основной модуль, сохранить/F7, открыть свою форму и скопировать фактические TrainingId/ThumbprintHex.
В общий серверный модуль УчебнаяАсинхроннаяПодписьPDF85 вставьте ТОЛЬКО supporting-модуль ниже. Сервер=Да, Вызов сервера=Да, Клиент=Нет, Глобальный=Нет, Привилегированный=Нет. Он проверяет свою пустую конфигурацию и экспортирует только собственную таблицу в байты. Подписание/ключевой контейнер работают у своего текущего Windows-клиента, не у учётной записи рабочего сервера.
Во время Ждать не закрывайте форму и не меняйте поля источника ключа. Метка/отпечаток копируются в локальные переменные до ожидания, Занято запрещает повторный старт; флаг очищается и при успехе, и при ошибке. Веб-/мобильный клиент и установка расширений не входят в этот опыт.
&НаКлиенте
Функция ПодготовитьСвойМенеджер()
Информация = СредстваКриптографии.ПолучитьИнформациюМодуляКриптографии("Microsoft Enhanced RSA and AES Cryptographic Provider", "", 24);
Если Информация = Неопределено Или ТипЗнч(Информация) <> Тип("ИнформацияМодуляКриптографии") Тогда
ВызватьИсключение "На своём Windows-стенде не найден требуемый провайдер";
КонецЕсли;
Если Информация.ТипМодуляКриптографии <> 24 Тогда
ВызватьИсключение "Нужен фактический CryptoAPI-провайдер типа24";
КонецЕсли;
АлгоритмSHA256 = "";
Для Каждого Алгоритм Из Информация.АлгоритмыХеширования Цикл
Если НРег(Алгоритм) = "sha256" Или НРег(Алгоритм) = "sha-256" Или Алгоритм = "2.16.840.1.101.3.4.2.1" Тогда
АлгоритмSHA256 = Алгоритм;
КонецЕсли;
КонецЦикла;
Если АлгоритмSHA256 = "" Тогда
ВызватьИсключение "Свой провайдер не подтвердил SHA256; другое имя не подставлять наугад";
КонецЕсли;
Менеджер = Новый МенеджерКриптографии("Microsoft Enhanced RSA and AES Cryptographic Provider", "", 24, ИспользованиеИнтерактивногоРежимаКриптографии.НеИспользовать);
Менеджер.АлгоритмХеширования = АлгоритмSHA256;
Менеджер.ВключениеСертификатовВПодпись = РежимВключенияСертификатовКриптографии.ВключатьСертификатСубъекта;
Менеджер.АдресаСерверовМетокВремени = Новый Массив;
Если Менеджер.АдресаСерверовМетокВремени.Количество() <> 0 Тогда
ВызватьИсключение "Урок не должен обращаться к внешнему серверу меток времени";
КонецЕсли;
Возврат Менеджер;
КонецФункции
&НаКлиенте
Функция НайтиСвойСертификат(Менеджер, Метка, ОтпечатокHex)
Если СтрДлина(ОтпечатокHex) <> 40 Тогда
ВызватьИсключение "Скопируйте весь SHA1-отпечаток из собственного PowerShell-опыта без пробелов";
КонецЕсли;
Отпечаток = ПолучитьДвоичныеДанныеИзHexСтроки(ОтпечатокHex);
Если Отпечаток.Размер() <> 20 Тогда
ВызватьИсключение "SHA1-отпечаток должен содержать20байт";
КонецЕсли;
Хранилище = Менеджер.ПолучитьХранилищеСертификатов(ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты,
РасположениеХранилищаСертификатовКриптографии.ДанныеПользователяОС);
Сертификат = Хранилище.НайтиПоОтпечатку(Отпечаток);
Если Сертификат = Неопределено Или ТипЗнч(Сертификат) <> Тип("СертификатКриптографии") Тогда
ВызватьИсключение "В собственном текущем Windows-профиле не найден именно созданный учебный сертификат";
КонецЕсли;
Если Base64Строка(Сертификат.Отпечаток) <> Base64Строка(Отпечаток) Тогда
ВызватьИсключение "Найден не свой точный отпечаток";
КонецЕсли;
CN = Неопределено;
Если Не Сертификат.Субъект.Свойство("CN", CN) Тогда
ВызватьИсключение "Нет собственного CN учебного сертификата";
КонецЕсли;
Если CN <> "Syntax Guide PDF Own85 " + Метка Тогда
ВызватьИсключение "CN должен совпасть с собственной уникальной меткой подготовки ключа";
КонецЕсли;
Возврат Сертификат;
КонецФункции
&НаКлиенте
Функция ПодготовитьСвоюПодпись(Документ, Сертификат, Метка)
Если Документ.КоличествоСтраниц() = 0 Тогда
ВызватьИсключение "Нужен собственный PDF с реальной первой страницей";
КонецЕсли;
Страница = Документ.Страницы.Получить(0);
Если Страница.Ориентация <> 0 Или Страница.Ширина - Страница.ПолеСлева - Страница.ПолеСправа < 80
Или Страница.Высота - Страница.ПолеСверху - Страница.ПолеСнизу < 60 Тогда
ВызватьИсключение "Собственная неповёрнутая страница должна вместить штамп10/45/70/15мм";
КонецЕсли;
Описание = Новый ОписаниеПодписиPDF;
Описание.Имя = "СвояПодпись85_" + Метка;
Описание.Сертификат = Сертификат;
Описание.ТипПодписи = ТипПодписиPDF.Утверждающая;
Описание.БлокировкаДокумента = Ложь;
Описание.НомерСтраницы = 1;
Описание.Лево = 10;
Описание.Верх = 45;
Описание.Ширина = 70;
Описание.Высота = 15;
Возврат Описание;
КонецФункции
&НаКлиенте
Асинх Функция ПрочитатьСвоиБайтыАсинх(Данные)
Поток = Данные.ОткрытьПотокДляЧтения();
Попытка
Документ = Новый ДокументPDF;
Ждать Документ.ПрочитатьАсинх(Поток, "");
Исключение
ОшибкаОперации = ОписаниеОшибки();
Попытка
Поток.Закрыть();
Исключение
ОшибкаОперации = ОшибкаОперации + " Закрытие своего входного потока: " + ОписаниеОшибки();
КонецПопытки;
ВызватьИсключение ОшибкаОперации;
КонецПопытки;
Поток.Закрыть();
Возврат Документ;
КонецФункции
&НаКлиенте
Асинх Функция ЗаписатьСвоиБайтыАсинх(Документ)
Поток = Новый ПотокВПамяти;
Попытка
Ждать Документ.ЗаписатьАсинх(Поток, "", ТипФайлаДокументаPDF.PDF);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Исключение
ОшибкаОперации = ОписаниеОшибки();
Попытка
Поток.Закрыть();
Исключение
ОшибкаОперации = ОшибкаОперации + " Закрытие своего выходного потока: " + ОписаниеОшибки();
КонецПопытки;
ВызватьИсключение ОшибкаОперации;
КонецПопытки;
Возврат Данные;
КонецФункции
&НаКлиенте
Процедура ПроверитьСвойОтветСертификата(Результат, Сертификат)
Если ТипЗнч(Результат) <> Тип("СертификатКриптографии")
Или Base64Строка(Результат.Отпечаток) <> Base64Строка(Сертификат.Отпечаток) Тогда
ВызватьИсключение "Await должен вернуть включённый сертификат собственного субъекта";
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьСвоиБайтыНаСервере()
Возврат УчебнаяАсинхроннаяПодписьPDF85.ПолучитьСвоиБайтыPDF();
КонецФункции
&НаКлиенте
Асинх Процедура Выполнить(Команда)
Если Занято Тогда
ВызватьИсключение "Дождитесь завершения своей текущей операции";
КонецЕсли;
Система = Новый СистемнаяИнформация;
Если (Система.ТипПлатформы <> ТипПлатформы.Windows_x86 И Система.ТипПлатформы <> ТипПлатформы.Windows_x86_64) Тогда
ВызватьИсключение "Нужен собственный тонкий Windows-клиент8.5.1.1343";
КонецЕсли;
Если Не ПодтверждаюСвойСтенд Тогда
ВызватьИсключение "Подтвердите только использование своего отдельного ключевого стенда";
КонецЕсли;
Метка = МеткаСертификата85;
ОтпечатокHex = ОтпечатокHex85;
UUID = Новый УникальныйИдентификатор(Метка);
Если Строка(UUID) <> Метка Тогда
ВызватьИсключение "Скопируйте фактическую метку собственного учебного сертификата";
КонецЕсли;
Занято = Истина;
Отчёт = "Собственная операция ещё не завершена";
Попытка
ДанныеPDF = ПолучитьСвоиБайтыНаСервере();
Документ = Ждать ПрочитатьСвоиБайтыАсинх(ДанныеPDF);
Менеджер = ПодготовитьСвойМенеджер();
Сертификат = НайтиСвойСертификат(Менеджер, Метка, ОтпечатокHex);
ДоПодписания = Ждать Документ.ПолучитьОписанияПодписейАсинх(Менеджер);
Если ТипЗнч(ДоПодписания) <> Тип("Массив") Или ДоПодписания.Количество() <> 0 Тогда
ВызватьИсключение "Собственный исходный PDF не должен содержать прежних подписей";
КонецЕсли;
Описание = ПодготовитьСвоюПодпись(Документ, Сертификат, Метка);
Штамп = Новый ТабличныйДокумент;
Штамп.Область(1, 1).Текст = "УЧЕБНЫЙ АСИНХРОННЫЙ САМОПОДПИСАННЫЙ ОБРАЗЕЦ";
Ждать Документ.ДобавитьПодписьАсинх(Менеджер, Описание, Штамп, Истина);
ПодписанныеБайты = Ждать ЗаписатьСвоиБайтыАсинх(Документ);
Если ПодписанныеБайты.Размер() = 0 Тогда
ВызватьИсключение "Не получены собственные подписанные PDF-байты";
КонецЕсли;
Копия = Ждать ПрочитатьСвоиБайтыАсинх(ПодписанныеБайты);
Описания = Ждать Копия.ПолучитьОписанияПодписейАсинх(Менеджер);
Если ТипЗнч(Описания) <> Тип("Массив") Или Описания.Количество() <> 1 Тогда
ВызватьИсключение "Из новых PDF-байтов должно вернуться одно описание собственной подписи";
КонецЕсли;
Подпись = Описания[0];
Если ТипЗнч(Подпись) <> Тип("ОписаниеПодписиPDF") Или Подпись.Имя <> Описание.Имя Тогда
ВызватьИсключение "Await описаний не вернул именно собственную добавленную подпись";
КонецЕсли;
ПроверитьСвойОтветСертификата(Подпись.Сертификат, Сертификат);
ДатаПодписи = Подпись.Дата;
Если ТипЗнч(ДатаПодписи) <> Тип("Дата") Или ДатаПодписи = Дата(1, 1, 1) Тогда
ВызватьИсключение "В своём описании нет заполненной native-даты; подстановка текущей даты запрещена";
КонецЕсли;
ПроверенныйСертификат = Ждать Копия.ПроверитьПодписьАсинх(Описание.Имя, Менеджер);
ПроверитьСвойОтветСертификата(ПроверенныйСертификат, Сертификат);
ВсеСертификаты = Ждать Копия.ПроверитьПодписиАсинх(Менеджер);
Если ТипЗнч(ВсеСертификаты) <> Тип("Массив") Или ВсеСертификаты.Количество() <> 1 Тогда
ВызватьИсключение "Await всех подписей должен вернуть один включённый собственный сертификат";
КонецЕсли;
ПроверитьСвойОтветСертификата(ВсеСертификаты[0], Сертификат);
Отчёт = "Все await завершены: собственная подпись и сертификаты проверены. Native-дата: " + Строка(ДатаПодписи)
+ ". Это не доверенная TSA-дата и не правовая оценка";
Исключение
Занято = Ложь;
Отчёт = "Свой асинхронный опыт не завершён: " + ОписаниеОшибки();
ВызватьИсключение Отчёт;
КонецПопытки;
Занято = Ложь;
КонецПроцедурыУчебнаяАсинхроннаяПодписьPDF85
Конфигуратор → Общие модули → УчебнаяАсинхроннаяПодписьPDF85 → Модуль
Полный серверный общий модуль: защита своего пустого стенда и создание только своих unsigned PDF-байтов в памяти. Не выполнялся.
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедуры
Функция СоздатьСобственныеБайтыPDF()
Таблица = Новый ТабличныйДокумент;
Таблица.КодЯзыка = "ru";
Таблица.Область(1, 1).Текст = "СОБСТВЕННЫЙ УЧЕБНЫЙ ОБРАЗЕЦ";
Таблица.Область(2, 1).Текст = "Книга";
Таблица.Область(2, 2).Текст = "3";
Таблица.Область(2, 3).Текст = "250";
Таблица.Область(2, 4).Текст = "750";
Таблица.Область(1, 1, 2, 4).ЦветФона = Новый Цвет(255, 255, 210);
Таблица.Область(, 1, , 1).ШиринаКолонки = 45;
Поток = Новый ПотокВПамяти;
Попытка
Таблица.Записать(Поток, ТипФайлаТабличногоДокумента.PDF);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Исключение
Поток.Закрыть();
ВызватьИсключение;
КонецПопытки;
Возврат Данные;
КонецФункции
Функция ПолучитьСвоиБайтыPDF() Экспорт
ПроверитьСвойПустойСтенд();
Возврат СоздатьСобственныеБайтыPDF();
КонецФункцииРазбор по шагам
Клиент проверяет точное имя своей конфигурации, версию/Windows и подтверждение учебного стенда. Supporting-серверный модуль отдельно проверяет отсутствие рабочих объектов/расширений ДО экспорта собственных байтов. Серверная защита не скопирована в контекст тонкого клиента.
Свои байты получают полный реальный источник: собственная таблица Книга/3/250/750 → PDF в ПотокВПамяти на сервере → ДвоичныеДанные в свою форму. Клиент открывает собственный поток чтения и ждёт ПрочитатьАсинх до его закрытия.
Полные клиентские функции проверяют настоящий CryptoAPI Type24/SHA256 и собственный CurrentUser-сертификат по20байтам отпечатка и CN с UUID. ВключатьСертификатСубъекта задан явно, TSA-массив пуст. Файл/ключ с неизвестным источником не принимается.
До подписи Ждать ПолучитьОписанияПодписейАсинх возвращает настоящий Массив: требуется0. Promise без Ждать не имеет готового количества; нельзя сравнить сам Promise с пустым массивом.
Собственное описание проверяет реальную первую страницу и поля, получает свой сертификат/имя и прямоугольник. Ждать ДобавитьПодписьАсинх ждёт завершения создания подписи; никакого нового готового ДокументPDF этот результат не обещает.
Новый выходной ПотокВПамяти передаётся ЗаписатьАсинх с ЯВНЫМ ПУСТЫМ паролем и PDF-форматом. Native-контракт запрещает запись подписанного PDF с непустым паролем. Только после Ждать поток закрывается с получением новых байтов.
Подписанные байты читаются новым независимым ДокументPDF через второй awaited ПрочитатьАсинх. ПолучитьОписанияПодписейАсинх у Копия должен вернуть1 ДО индекса0; сверяются реальный тип, имя, свой отпечаток и readonly native-дата.
Ждать ПроверитьПодписьАсинх(Имя, Менеджер) возвращает СертификатКриптографии. В отличие от синхронного overload, третьего выходного параметра нет. Полученный сертификат проверяется по типу/своему отпечатку, не по непустому представлению.
Ждать ПроверитьПодписиАсинх(Менеджер) возвращает Массив сертификатов. В отличие от синхронного overload, второго выходного параметра нет. Проверяем Array/количество1 ДО индекса0 и тот же фактический отпечаток.
Потоки чтения закрываются после завершившегося await; при исключении ошибка закрытия добавляется к исходной ошибке, не превращает её в успех. Выходной поток закрывается с байтами при успехе и отдельно на ошибке. Флаг Занято восстанавливается независимо от итогового статуса.
Строка успеха появляется только ПОСЛЕ всех awaited операций и сравнений. Ошибка любого этапа формирует отчёт об ошибке и повторно выбрасывается. CA/отзыв/правовая сила и доверенная TSA-дата не обещаются.
Как проверить результат
Будущий результат на полностью подготовленном своём тонком клиенте: исходных подписей0, из новых байтов возвращается1; фактическое имя/сертификат/дата совпадают с собственным источником, оба awaited метода проверки возвращают ожидаемые реальные типы. Занято в конце Ложь.
Будущий отрицательный контроль: у ПроверитьПодписьАсинх временно передайте Описание.Имя + "_отсутствует". Promise должен завершиться ошибкой, отчёт успеха не появиться, Занято вернуться в Ложь. Не заменяйте имя другой подписью автоматически.
Будущий контроль результатов: после Ждать проверки всех подписей временно замените ВсеСертификаты на Новый Массив. Проверка количества должна отказать ДО индекса0, несмотря на ранее завершённые операции.
Будущий контроль источника: перед чтением Копия подайте ДанныеPDF вместо ПодписанныеБайты. Массив описаний будет0 и должен быть отвергнут. Верните новые подписанные байты после опыта.
Будущий контроль повторного старта: вызовите собственную кнопку повторно, пока Занято=Истина. Второй запуск должен отказать до открытия потока/использования ключа. Не закрывайте форму для имитации отмены.
runtimeVerifiedScenarios=0: BSL, тонкий клиент, ключи, подпись, PDF-потоки и GUI здесь не запускались. Успех статических проверок не удостоверяет завершение Promise на конкретном провайдере.
Ожидаемый результат
Все awaited PDF-операции завершены, из новых своих подписанных байтов получены и проверены реальные описание, дата и сертификаты; флаг занятости очищен, доверие/правовая сила не заявлены
На что обратить внимание
Это отдельный урок со своим закрытым ключом, не продолжение опыта с публичным DER Syntax Guide Training Only. Публичный DER из предыдущего урока не может заменить этот ключ.
Создание учебного ключа — осознанное будущее изменение ТОЛЬКО своего изолированного профиля. Оно не выполнялось инструментами этого чата. NonExportable не означает, что ключ исчезнет после опыта или что он доверенный.
Чтение описания/даты — не эквивалент ПроверитьПодпись, проверки CA/отзыва или доверенной TSA-метки. Никакого правового вывода по self-signed образцу не делается.
Текст штампа — визуальное представление, не сама криптографическая подпись. Не обещается, что все PDF-просмотрщики доверяют self-signed сертификату или одинаково показывают штамп.
Ключ принадлежит текущему учебному Windows-клиенту. Сервер создаёт только свои PDF-байты и ключ не использует; ошибка источника не разрешает переключиться на чужой профиль или область ДанныеКомпьютера.
Новый ОписаниеПодписиPDF — настройки до подписи, не источник фактической readonly-даты. Её читаем только из awaited описаний новых подписанных PDF-байтов.
Четыре PDF Async-метода доступны клиенту, не серверу. Синхронные методы подписания/чтения/проверки не вставлены вместо Async в основном модуле формы.
Promise надо дождаться внутри Асинх Процедура/Функция. ПолучитьОписанияПодписейАсинх возвращает Array после ожидания, ПроверитьПодписьАсинх — Certificate, ПроверитьПодписиАсинх — Array; это разные контракты.
Асинхронное ожидание — не фоновая серверная работа и не гарантия, что синхронная инициализация криптографии не блокирует интерфейс. Разрешённый синхронный режим указан явно; браузерные расширения не устанавливаются.
Пустой пароль записи обязателен для этого подписанного образца. Непустой пароль должен вызвать native-ошибку; её нельзя скрыть и вернуть старые байты как новый результат.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.