Получает массив, содержащий описания присоединенных к PDF-документу электронных подписей.
Синтаксис
ПолучитьОписанияПодписей(<МенеджерКриптографии>)Полное описание, параметры и ограничения
ДокументPDF.ПолучитьОписанияПодписей (PDFDocument.GetSignatureDescriptions)
ДокументPDF (PDFDocument)
ПолучитьОписанияПодписей (GetSignatureDescriptions)
Доступен, начиная с версии 8.3.21.
Синтаксис:
ПолучитьОписанияПодписей(<МенеджерКриптографии>)
Параметры:
<МенеджерКриптографии> (обязательный)
Тип: МенеджерКриптографии.
Менеджер криптографии.
Возвращаемое значение:
Тип: Массив.
Массив объектов типа ОписаниеПодписиPDF.
Описание:
Получает массив, содержащий описания присоединенных к PDF-документу электронных подписей.
Доступность:
Тонкий клиент, сервер, толстый клиент.
Использование в версии:
Доступен, начиная с версии 8.3.21.
Методическая информация
Практические примеры
Подписать свой PDF учебным ключом и прочитать фактическую readonly-дату обратно
Полная подготовка собственного Windows-ключа, точный поиск сертификата по отпечатку и CN, локальная подпись своего PDF в памяти и повторное чтение новых подписанных байтов. Дата берётся только из настоящего описания подписи, не из текущих часов и не из пустого шаблона.
Где и как запускать
Полный серверный общий модуль своего Windows файлового стенда: будущий ручной опыт с собственным ключом и PDF-байтами только в памяти. Подпись и создание ключа здесь не выполнялись.
Подготовка
НОВАЯ пустая файловая учебная база УчебнаяДатаПодписи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. Это документирование будущего учебного опыта, не выполненное создание ключа.
Конфигуратор → Общие модули → УчебнаяДатаПодписиPDF85: Сервер=Да, Вызов сервера=Да, Клиент=Нет, Глобальный=Нет, Привилегированный=Нет. Вставьте весь основной модуль. Работайте именно в своей файловой базе под тем же собственным Windows-пользователем, который вручную подготовил сертификат.
Своя управляемая форма: реквизиты МеткаСертификата85 Строка100, ОтпечатокHex85 Строка40, ПодтверждаюСвойСтенд Булево начально Ложь, Отчёт Строка0. Поля с теми же путями, Отчёт многострочный ТолькоПросмотр=Да. Команда/кнопка Выполнить, действие Выполнить. Вставьте полный supporting-модуль; сохранить/F7, открыть свою форму, скопировать фактические TrainingId/ThumbprintHex, подтвердить только собственный учебный опыт.
Учебный сертификат и ключ остаются в собственном Windows-профиле после закрытия1С; урок их автоматически не удаляет. Администратор отдельного стенда отвечает за его очистку после обучения. Не переносите опыт в рабочий профиль и не выдавайте закрытие формы за удаление ключа.
Ни PowerShell-команды, ни CryptoAPI/1С, ни AddSignature, ни GUI/сервер/ключи/подпись здесь не запускались. runtimeVerifiedScenarios=0.
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 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;
Документ.Прочитать(Поток);
Поток.Закрыть();
Исключение
Поток.Закрыть();
ВызватьИсключение;
КонецПопытки;
Возврат Документ;
КонецФункции
Функция ЗаписатьСобственныйДокумент(Документ, ТипФайла)
Поток = Новый ПотокВПамяти;
Попытка
Документ.Записать(Поток, "", ТипФайла);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Исключение
Поток.Закрыть();
ВызватьИсключение;
КонецПопытки;
Возврат Данные;
КонецФункции
Функция ПодготовитьСвойМенеджер()
Информация = СредстваКриптографии.ПолучитьИнформациюМодуляКриптографии("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;
Возврат Описание;
КонецФункции
Функция ПрочитатьСвоюДату(Документ, Менеджер, Имя, Сертификат)
Описания = Документ.ПолучитьОписанияПодписей(Менеджер);
Если ТипЗнч(Описания) <> Тип("Массив") Или Описания.Количество() <> 1 Тогда
ВызватьИсключение "В прочитанных собственных PDF-байтах должно быть ровно одно реальное описание добавленной подписи";
КонецЕсли;
Подпись = Описания[0];
Если ТипЗнч(Подпись) <> Тип("ОписаниеПодписиPDF") Или Подпись.Имя <> Имя Тогда
ВызватьИсключение "Из документа должно вернуться реальное описание собственной добавленной подписи";
КонецЕсли;
Если ТипЗнч(Подпись.Сертификат) <> Тип("СертификатКриптографии")
Или Base64Строка(Подпись.Сертификат.Отпечаток) <> Base64Строка(Сертификат.Отпечаток) Тогда
ВызватьИсключение "В подписи должен находиться именно включённый сертификат своего субъекта";
КонецЕсли;
ДатаПодписи = Подпись.Дата;
Если ТипЗнч(ДатаПодписи) <> Тип("Дата") Или ДатаПодписи = Дата(1, 1, 1) Тогда
ВызватьИсключение "Описание не содержит заполненной native-даты; текущую дату вместо неё подставлять нельзя";
КонецЕсли;
Возврат ДатаПодписи;
КонецФункции
Функция ВыполнитьПример(Метка, ОтпечатокHex, Согласие) Экспорт
ПроверитьСвойПустойСтенд();
Система = Новый СистемнаяИнформация;
Если Система.ТипПлатформы <> ТипПлатформы.Windows_x86 И Система.ТипПлатформы <> ТипПлатформы.Windows_x86_64 Тогда
ВызватьИсключение "Нужен только собственный Windows-стенд с подготовленным CryptoAPI-ключом";
КонецЕсли;
Если Не Согласие Тогда
ВызватьИсключение "Подтвердите использование только собственного учебного ключа на отдельном стенде";
КонецЕсли;
UUID = Новый УникальныйИдентификатор(Метка);
Если Строка(UUID) <> Метка Тогда
ВызватьИсключение "Скопируйте полную фактическую метку собственного сертификата";
КонецЕсли;
Менеджер = ПодготовитьСвойМенеджер();
Сертификат = НайтиСвойСертификат(Менеджер, Метка, ОтпечатокHex);
ДанныеPDF = СоздатьСобственныеБайтыPDF();
Документ = ПрочитатьСобственныйДокумент(ДанныеPDF);
ДоПодписания = Документ.ПолучитьОписанияПодписей(Менеджер);
Если ТипЗнч(ДоПодписания) <> Тип("Массив") Или ДоПодписания.Количество() <> 0 Тогда
ВызватьИсключение "Собственный исходный экспорт не должен содержать прежних подписей";
КонецЕсли;
Описание = ПодготовитьСвоюПодпись(Документ, Сертификат, Метка);
Штамп = Новый ТабличныйДокумент;
Штамп.Область(1, 1).Текст = "УЧЕБНЫЙ САМОПОДПИСАННЫЙ ОБРАЗЕЦ";
Документ.ДобавитьПодпись(Менеджер, Описание, Штамп, Истина);
ПодписанныеБайты = ЗаписатьСобственныйДокумент(Документ, ТипФайлаДокументаPDF.PDF);
Если ПодписанныеБайты.Размер() = 0 Тогда
ВызватьИсключение "Запись собственного подписанного PDF не дала байтов";
КонецЕсли;
Копия = ПрочитатьСобственныйДокумент(ПодписанныеБайты);
ДатаПодписи = ПрочитатьСвоюДату(Копия, Менеджер, Описание.Имя, Сертификат);
Возврат "Дата из реально прочитанной своей подписи: " + Строка(ДатаПодписи)
+ ". Это не доверенная метка времени и не проверка юридической силы";
КонецФункцииУчебнаяДатаПодписиPDF85
Своя управляемая форма → Модуль
Полный клиентский launcher с server wrapper и явными реквизитами собственного ключевого стенда; не выполнялся.
&НаКлиенте
Процедура Выполнить(Команда)
Отчёт = ВыполнитьНаСервере(МеткаСертификата85, ОтпечатокHex85, ПодтверждаюСвойСтенд);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ВыполнитьНаСервере(Метка, ОтпечатокHex, Согласие)
Возврат УчебнаяДатаПодписиPDF85.ВыполнитьПример(Метка, ОтпечатокHex, Согласие);
КонецФункцииРазбор по шагам
Защита требует собственную пустую конфигурацию, точную платформу и Windows. Подтверждение оператора разрешает только свой учебный ключ; настоящий UUID берётся из отдельного опыта подготовки, а не придумывается в коде1С.
Сведения фактического провайдера должны подтвердить Type24 и поддерживаемое имя SHA256. В менеджер передаётся именно имя из его списка, не произвольная строка неизвестного алгоритма. Если провайдер/алгоритм отсутствует, урок отказывает.
ПерсональныеСертификаты + ДанныеПользователяОС открываются явно. НайтиПоОтпечатку получает реальные20байт SHA1 из полного40-символьного Hex. Неопределено — ошибка подготовки собственного ключа, не повод искать в другом хранилище.
Найденный сертификат проверяется по точному отпечатку и собственному CN с UUID. Название само по себе недостаточно. Отпечаток SHA1 здесь идентифицирует сертификат; подпись PDF настраивается на SHA256, это разные задачи.
У self-signed образца явно задаём ВключатьСертификатСубъекта. Default ВключатьЦепочкуБезКорневого не подходит как неявное обещание включения самоподписанного сертификата. TSA-массив пуст, сторонние сертификаты/корни не импортируются.
Полный код создаёт своё PDF-содержимое Книга/3/250/750 в памяти. До подписания ПолучитьОписанияПодписей должен вернуть настоящий Массив с количеством0. Нельзя подавать чужой PDF с уже существующей подписью.
Реальная первая страница и её поля проверяются до задания штампа. Утверждающая подпись с БлокировкаДокумента=Ложь, существующей страницей1 и своим именем/сертификатом передаётся ДобавитьПодпись вместе с собственным штампом и явным Истина учёта ориентации.
Подписанный документ записывается в новый ПотокВПамяти. ДвоичныеДанные получаются вместе с закрытием потока, затем читаются в НОВЫЙ ДокументPDF. Это не чтение предварительного Описание и не повторное чтение исходных неподписанных байтов.
У повторно прочитанного документа получаем настоящий Массив описаний; количество1 проверяется ДО индекса0. Тип, имя и включённый сертификат должны совпасть с собственным источником. Только тогда читается readonly Подпись.Дата.
Дата обязана быть native-типом Дата и не пустой. Если платформа не возвращает заполненную дату, урок выдаёт ошибку; он не подставляет ТекущаяДата. Часовой пояс и независимую доверенную метку времени этот вывод не удостоверяет.
Этот урок получает дату собственной добавленной подписи, но не вызывает ПроверитьПодпись/ПроверитьПодписи и не заявляет проверку доверенной цепочки или юридическую силу. Эти операции требуют отдельного разбора критериев проверки.
Как проверить результат
Будущий результат на подготовленном собственном стенде: исходных подписей0, в новых прочитанных PDF-байтах ровно1 с собственным именем/отпечатком, из неё возвращается заполненная Дата. Ошибка провайдера, ключа, сертификата или даты не считается успехом.
Будущий отрицательный контроль: при той же собственной метке вставьте заведомо отсутствующий40-символьный Hex-отпечаток. Поиск должен отказать ДО ДобавитьПодпись, без перебора чужих сертификатов и без смены области хранилища.
Будущий контроль источника: временно замените ПрочитатьСобственныйДокумент(ПодписанныеБайты) на чтение ДанныеPDF. ПолучитьОписанияПодписей вернёт0, и проверка должна отказать до индекса0/Дата. Верните новые подписанные байты после опыта.
Будущий контроль принадлежности: измените только МеткаСертификата85 на другой свой UUID, сохранив прежний отпечаток. CN должен не совпасть и остановить операцию ДО подписи. Нельзя убрать сравнение CN для прохождения.
runtimeVerifiedScenarios=0. Поддержка конкретного провайдера, фактическая подпись/сохранение даты и внешний вид штампа требуют будущего отдельного ручного опыта; здесь проверены только исходники и контракты.
Ожидаемый результат
Дата прочитана из собственной добавленной подписи после записи/чтения новых PDF-байтов; дата не придумана, доверие/юридическая сила не заявлены
На что обратить внимание
Это отдельный урок со своим закрытым ключом, не продолжение опыта с публичным DER Syntax Guide Training Only. Публичный DER из предыдущего урока не может заменить этот ключ.
Сертификат живёт в Windows-профиле, а не в базе1С. В файловом стенде и консоли подготовки должен быть тот же учебный Windows-пользователь. В кластере под другим аккаунтом точный поиск должен не найти сертификат; обходить это сменой области запрещено.
Создание учебного ключа — осознанное будущее изменение ТОЛЬКО своего изолированного профиля. Оно не выполнялось инструментами этого чата. NonExportable не означает, что ключ исчезнет после опыта или что он доверенный.
Чтение описания/даты — не эквивалент ПроверитьПодпись, проверки CA/отзыва или доверенной TSA-метки. Никакого правового вывода по self-signed образцу не делается.
Ни новый ОписаниеПодписиPDF, ни текущая дата не являются источником фактической даты подписанного PDF. Источник здесь — только ПолучитьОписанияПодписей у повторно прочитанных подписанных байтов.
Текст штампа — визуальное представление, не сама криптографическая подпись. Не обещается, что все PDF-просмотрщики доверяют self-signed сертификату или одинаково показывают штамп.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.
Проверить свою PDF-подпись по имени и все подписи документа без фиктивного Булево
Полный собственный ключевой стенд, подписание PDF в памяти и чтение новых байтов. Два native-метода проверки вызываются как процедуры: неудача — исключение; отдельные выходные параметры сертификата и массива дополнительно сверяются с собственным источником.
Где и как запускать
Полный серверный общий модуль своего Windows файлового стенда: будущий ручной опыт с собственным ключом и PDF-байтами только в памяти. Подпись и создание ключа здесь не выполнялись.
Подготовка
НОВАЯ пустая файловая учебная база УчебнаяПроверкаПодписи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. Это документирование будущего учебного опыта, не выполненное создание ключа.
Конфигуратор → Общие модули → УчебнаяПроверкаПодписиPDF85: Сервер=Да, Вызов сервера=Да, Клиент=Нет, Глобальный=Нет, Привилегированный=Нет. Вставьте весь основной модуль. Работайте именно в своей файловой базе под тем же собственным Windows-пользователем, который вручную подготовил сертификат.
Своя управляемая форма: реквизиты МеткаСертификата85 Строка100, ОтпечатокHex85 Строка40, ПодтверждаюСвойСтенд Булево начально Ложь, Отчёт Строка0. Поля с теми же путями, Отчёт многострочный ТолькоПросмотр=Да. Команда/кнопка Выполнить, действие Выполнить. Вставьте полный supporting-модуль; сохранить/F7, открыть свою форму, скопировать фактические TrainingId/ThumbprintHex, подтвердить только собственный учебный опыт.
Учебный сертификат и ключ остаются в собственном Windows-профиле после закрытия1С; урок их автоматически не удаляет. Администратор отдельного стенда отвечает за его очистку после обучения. Не переносите опыт в рабочий профиль и не выдавайте закрытие формы за удаление ключа.
Ни PowerShell-команды, ни CryptoAPI/1С, ни AddSignature, ни GUI/сервер/ключи/подпись здесь не запускались. runtimeVerifiedScenarios=0.
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 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;
Документ.Прочитать(Поток);
Поток.Закрыть();
Исключение
Поток.Закрыть();
ВызватьИсключение;
КонецПопытки;
Возврат Документ;
КонецФункции
Функция ЗаписатьСобственныйДокумент(Документ, ТипФайла)
Поток = Новый ПотокВПамяти;
Попытка
Документ.Записать(Поток, "", ТипФайла);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Исключение
Поток.Закрыть();
ВызватьИсключение;
КонецПопытки;
Возврат Данные;
КонецФункции
Функция ПодготовитьСвойМенеджер()
Информация = СредстваКриптографии.ПолучитьИнформациюМодуляКриптографии("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;
Возврат Описание;
КонецФункции
Функция ПрочитатьСвоюДату(Документ, Менеджер, Имя, Сертификат)
Описания = Документ.ПолучитьОписанияПодписей(Менеджер);
Если ТипЗнч(Описания) <> Тип("Массив") Или Описания.Количество() <> 1 Тогда
ВызватьИсключение "В прочитанных собственных PDF-байтах должно быть ровно одно реальное описание добавленной подписи";
КонецЕсли;
Подпись = Описания[0];
Если ТипЗнч(Подпись) <> Тип("ОписаниеПодписиPDF") Или Подпись.Имя <> Имя Тогда
ВызватьИсключение "Из документа должно вернуться реальное описание собственной добавленной подписи";
КонецЕсли;
Если ТипЗнч(Подпись.Сертификат) <> Тип("СертификатКриптографии")
Или Base64Строка(Подпись.Сертификат.Отпечаток) <> Base64Строка(Сертификат.Отпечаток) Тогда
ВызватьИсключение "В подписи должен находиться именно включённый сертификат своего субъекта";
КонецЕсли;
ДатаПодписи = Подпись.Дата;
Если ТипЗнч(ДатаПодписи) <> Тип("Дата") Или ДатаПодписи = Дата(1, 1, 1) Тогда
ВызватьИсключение "Описание не содержит заполненной native-даты; текущую дату вместо неё подставлять нельзя";
КонецЕсли;
Возврат ДатаПодписи;
КонецФункции
Функция ВыполнитьПример(Метка, ОтпечатокHex, Согласие) Экспорт
ПроверитьСвойПустойСтенд();
Система = Новый СистемнаяИнформация;
Если Система.ТипПлатформы <> ТипПлатформы.Windows_x86 И Система.ТипПлатформы <> ТипПлатформы.Windows_x86_64 Тогда
ВызватьИсключение "Нужен только собственный Windows-стенд с подготовленным CryptoAPI-ключом";
КонецЕсли;
Если Не Согласие Тогда
ВызватьИсключение "Подтвердите использование только собственного учебного ключа на отдельном стенде";
КонецЕсли;
UUID = Новый УникальныйИдентификатор(Метка);
Если Строка(UUID) <> Метка Тогда
ВызватьИсключение "Скопируйте полную фактическую метку собственного сертификата";
КонецЕсли;
Менеджер = ПодготовитьСвойМенеджер();
Сертификат = НайтиСвойСертификат(Менеджер, Метка, ОтпечатокHex);
ДанныеPDF = СоздатьСобственныеБайтыPDF();
Документ = ПрочитатьСобственныйДокумент(ДанныеPDF);
ДоПодписания = Документ.ПолучитьОписанияПодписей(Менеджер);
Если ТипЗнч(ДоПодписания) <> Тип("Массив") Или ДоПодписания.Количество() <> 0 Тогда
ВызватьИсключение "Собственный исходный экспорт не должен содержать прежних подписей";
КонецЕсли;
Описание = ПодготовитьСвоюПодпись(Документ, Сертификат, Метка);
Штамп = Новый ТабличныйДокумент;
Штамп.Область(1, 1).Текст = "УЧЕБНЫЙ САМОПОДПИСАННЫЙ ОБРАЗЕЦ";
Документ.ДобавитьПодпись(Менеджер, Описание, Штамп, Истина);
ПодписанныеБайты = ЗаписатьСобственныйДокумент(Документ, ТипФайлаДокументаPDF.PDF);
Если ПодписанныеБайты.Размер() = 0 Тогда
ВызватьИсключение "Запись собственного подписанного PDF не дала байтов";
КонецЕсли;
Копия = ПрочитатьСобственныйДокумент(ПодписанныеБайты);
СертификатОдиночнойПроверки = Неопределено;
Копия.ПроверитьПодпись(Описание.Имя, Менеджер, СертификатОдиночнойПроверки);
Если ТипЗнч(СертификатОдиночнойПроверки) <> Тип("СертификатКриптографии")
Или Base64Строка(СертификатОдиночнойПроверки.Отпечаток) <> Base64Строка(Сертификат.Отпечаток) Тогда
ВызватьИсключение "Одиночная проверка должна вернуть включённый сертификат именно своего субъекта";
КонецЕсли;
СертификатыВсехПодписей = Новый Массив;
Копия.ПроверитьПодписи(Менеджер, СертификатыВсехПодписей);
Если ТипЗнч(СертификатыВсехПодписей) <> Тип("Массив") Или СертификатыВсехПодписей.Количество() <> 1 Тогда
ВызватьИсключение "Проверка всех подписей должна вернуть ровно один собственный сертификат";
КонецЕсли;
СертификатВсех = СертификатыВсехПодписей[0];
Если ТипЗнч(СертификатВсех) <> Тип("СертификатКриптографии")
Или Base64Строка(СертификатВсех.Отпечаток) <> Base64Строка(Сертификат.Отпечаток) Тогда
ВызватьИсключение "Все подписи должны быть проверены с единственным включённым собственным сертификатом";
КонецЕсли;
ДатаПодписи = ПрочитатьСвоюДату(Копия, Менеджер, Описание.Имя, Сертификат);
Возврат "Native-проверки одной и всех своих PDF-подписей завершились без исключений. Дата своей подписи: " + Строка(ДатаПодписи)
+ ". Это не доверенная метка времени и не проверка юридической силы";
КонецФункцииУчебнаяПроверкаПодписиPDF85
Своя управляемая форма → Модуль
Полный клиентский launcher с server wrapper и явными реквизитами собственного ключевого стенда; не выполнялся.
&НаКлиенте
Процедура Выполнить(Команда)
Отчёт = ВыполнитьНаСервере(МеткаСертификата85, ОтпечатокHex85, ПодтверждаюСвойСтенд);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ВыполнитьНаСервере(Метка, ОтпечатокHex, Согласие)
Возврат УчебнаяПроверкаПодписиPDF85.ВыполнитьПример(Метка, ОтпечатокHex, Согласие);
КонецФункцииРазбор по шагам
Защита требует собственную пустую конфигурацию, точную платформу и Windows. Подтверждение оператора разрешает только свой учебный ключ; настоящий UUID берётся из отдельного опыта подготовки, а не придумывается в коде1С.
Сведения фактического провайдера должны подтвердить Type24 и поддерживаемое имя SHA256. В менеджер передаётся именно имя из его списка, не произвольная строка неизвестного алгоритма. Если провайдер/алгоритм отсутствует, урок отказывает.
ПерсональныеСертификаты + ДанныеПользователяОС открываются явно. НайтиПоОтпечатку получает реальные20байт SHA1 из полного40-символьного Hex. Неопределено — ошибка подготовки собственного ключа, не повод искать в другом хранилище.
Найденный сертификат проверяется по точному отпечатку и собственному CN с UUID. Название само по себе недостаточно. Отпечаток SHA1 здесь идентифицирует сертификат; подпись PDF настраивается на SHA256, это разные задачи.
У self-signed образца явно задаём ВключатьСертификатСубъекта. Default ВключатьЦепочкуБезКорневого не подходит как неявное обещание включения самоподписанного сертификата. TSA-массив пуст, сторонние сертификаты/корни не импортируются.
Полный код создаёт своё PDF-содержимое Книга/3/250/750 в памяти. До подписания ПолучитьОписанияПодписей должен вернуть настоящий Массив с количеством0. Нельзя подавать чужой PDF с уже существующей подписью.
Реальная первая страница и её поля проверяются до задания штампа. Утверждающая подпись с БлокировкаДокумента=Ложь, существующей страницей1 и своим именем/сертификатом передаётся ДобавитьПодпись вместе с собственным штампом и явным Истина учёта ориентации.
Подписанный документ записывается в новый ПотокВПамяти. ДвоичныеДанные получаются вместе с закрытием потока, затем читаются в НОВЫЙ ДокументPDF. Это не чтение предварительного Описание и не повторное чтение исходных неподписанных байтов.
У повторно прочитанного документа получаем настоящий Массив описаний; количество1 проверяется ДО индекса0. Тип, имя и включённый сертификат должны совпасть с собственным источником. Только тогда читается readonly Подпись.Дата.
Дата обязана быть native-типом Дата и не пустой. Если платформа не возвращает заполненную дату, урок выдаёт ошибку; он не подставляет ТекущаяДата. Часовой пояс и независимую доверенную метку времени этот вывод не удостоверяет.
После записи подписанного PDF и чтения новых байтов Копия.ПроверитьПодпись получает ТОЧНОЕ собственное имя, настоящий менеджер и отдельную переменную СертификатОдиночнойПроверки. Это выходной параметр: изначально Неопределено, он не подменён заранее собственным сертификатом.
ПроверитьПодпись и ПроверитьПодписи не возвращают Булево. Не пишем Если Копия.ПроверитьПодпись(...) Тогда. Native-неудача генерирует исключение; такой опыт остановится и не выдаст строку успеха.
Менеджер ранее явно включил сертификат субъекта в подпись. После одиночной проверки выходной сертификат обязан иметь настоящий native-тип и точный отпечаток собственного источника. Непустая произвольная переменная не принимается за правильный результат.
Для ПроверитьПодписи создаётся новый пустой Массив и передаётся вторым выходным параметром. После native-проверки сверяются его тип и количество1 ДО индекса0; единственный сертификат также обязан совпасть с собственным отпечатком.
Только после обеих проверок и выходных сертификатов читается фактическая дата из настоящего описания подписанного документа. Результат различает native-успех операций и доверие/правовую силу: собственный self-signed сертификат не становится доверенным корнем.
Как проверить результат
Будущий результат на подготовленном собственном стенде: исходных подписей0, в новых прочитанных PDF-байтах ровно1 с собственным именем/отпечатком, из неё возвращается заполненная Дата. Ошибка провайдера, ключа, сертификата или даты не считается успехом.
Будущий отрицательный контроль: при той же собственной метке вставьте заведомо отсутствующий40-символьный Hex-отпечаток. Поиск должен отказать ДО ДобавитьПодпись, без перебора чужих сертификатов и без смены области хранилища.
Будущий контроль источника: временно замените ПрочитатьСобственныйДокумент(ПодписанныеБайты) на чтение ДанныеPDF. ПолучитьОписанияПодписей вернёт0, и проверка должна отказать до индекса0/Дата. Верните новые подписанные байты после опыта.
Будущий контроль принадлежности: измените только МеткаСертификата85 на другой свой UUID, сохранив прежний отпечаток. CN должен не совпасть и остановить операцию ДО подписи. Нельзя убрать сравнение CN для прохождения.
runtimeVerifiedScenarios=0. Поддержка конкретного провайдера, фактическая подпись/сохранение даты и внешний вид штампа требуют будущего отдельного ручного опыта; здесь проверены только исходники и контракты.
Будущий отрицательный контроль имени: в одиночной проверке временно передайте Описание.Имя + "_отсутствует". Native-метод должен выдать исключение, а код не должен дойти до вывода успеха или заменить имя подходящей чужой подписью.
Будущий контроль выходного параметра: после одиночной native-проверки временно задайте СертификатОдиночнойПроверки=Неопределено. Дополнительная проверка типа должна отказать, даже если сама native-операция не выбросила исключение.
При исключении ОшибкаПроверкиПодписи нельзя автоматически импортировать self-signed образец в доверенные корни, менять параметры рабочего профиля или объявлять успех. Запишите диагностику только собственного стенда; фактические требования его провайдера проверяются отдельно.
Ожидаемый результат
Одиночная и общая native-проверки собственного подписанного PDF завершились без исключений; оба выходных сертификата совпали с источником, доверие/юридическая сила не заявлены
На что обратить внимание
Это отдельный урок со своим закрытым ключом, не продолжение опыта с публичным DER Syntax Guide Training Only. Публичный DER из предыдущего урока не может заменить этот ключ.
Сертификат живёт в Windows-профиле, а не в базе1С. В файловом стенде и консоли подготовки должен быть тот же учебный Windows-пользователь. В кластере под другим аккаунтом точный поиск должен не найти сертификат; обходить это сменой области запрещено.
Создание учебного ключа — осознанное будущее изменение ТОЛЬКО своего изолированного профиля. Оно не выполнялось инструментами этого чата. NonExportable не означает, что ключ исчезнет после опыта или что он доверенный.
Ни новый ОписаниеПодписиPDF, ни текущая дата не являются источником фактической даты подписанного PDF. Источник здесь — только ПолучитьОписанияПодписей у повторно прочитанных подписанных байтов.
Текст штампа — визуальное представление, не сама криптографическая подпись. Не обещается, что все PDF-просмотрщики доверяют self-signed сертификату или одинаково показывают штамп.
ПолучитьОписанияПодписей в предыдущем уроке только читало описания. Здесь два метода native-проверки действительно вызываются у повторно прочитанного документа. Их исключения не перехватываются для превращения в успех.
Выходной Сертификат и выходной Массив — разные формы результата. Первый не создаётся через Новый пустой сертификат, второй не сравнивается с Булево. Не путайте их с Promise-результатами асинхронных overloads.
Успешная native-проверка собственного образца — не заявление юридической действительности, доверия CA, проверки отзыва или доверенной TSA-даты. Ошибка любой операции остаётся ошибкой этого будущего ручного опыта.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.