Сертификаты ключей электронной подписи и шифрования / Шифрование данных / Модуль формы

файл
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ОписаниеПеременных

&НаКлиенте
Перем ВнутренниеДанные, ОписаниеДанных, ФормаОбъекта, ОбработкаПослеПредупреждения, ТекущийСписокПредставлений;

#КонецОбласти

#Область ОбработчикиСобытийФормы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	Если ЗначениеЗаполнено(Параметры.НаборСертификатов) Тогда
		УказанНеизменяемыйНаборСертификатов = Истина;
		ЗаполнитьСертификатыШифрованияИзНабора(Параметры.НаборСертификатов);
		Если НаборСертификатов.Количество() = 0 И Параметры.ИзменятьНабор Тогда
			// Если все сертификаты набора ссылочные и изменение набора разрешено,
			// то взаимодействие с пользователем обычное, как будто он сам их добавил.
			УказанНеизменяемыйНаборСертификатов = Ложь;
		КонецЕсли;
	КонецЕсли;
	
	ЭлектроннаяПодписьСлужебный.НастроитьФормуПодписанияШифрованияРасшифровки(ЭтотОбъект, Истина);
	
	Если УказанНеизменяемыйНаборСертификатов Тогда
		Элементы.Сертификат.Видимость = Ложь;
		Элементы.ГруппаСертификатыШифрования.Заголовок = Элементы.ГруппаУказанныйНаборСертификатов.Заголовок;
		Элементы.СертификатыШифрования.ТолькоПросмотр = Истина;
		Элементы.СертификатыШифрованияПодобрать.Доступность = Ложь;
		ЗаполнитьПрограммуШифрованияНаСервере();
	КонецЕсли;
	
	Если ЭлектроннаяПодписьСлужебный.ИспользоватьСервисОблачнойПодписи() Тогда
		МодульСервисКриптографииDSSПодтверждениеСервер = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSSПодтверждениеСервер");
		МодульСервисКриптографииDSSПодтверждениеСервер.ПодготовитьГруппуПодтверждения(ЭтотОбъект, "Шифрование",
				"ПодборИзСправочника",
				"ГруппаКонтейнер",
				,
				"ГруппаКомандыПодтверждения");
		МодульСервисКриптографииDSSПодтверждениеСервер.ПодтверждениеПриИзмененииСертификата(ЭтотОбъект, ПолучитьОсновнойСертификат());
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	Если ВнутренниеДанные = Неопределено Тогда
		Отказ = Истина;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ИмяПоляАктивизироватьПоУмолчанию) Тогда
		ТекущийЭлемент = Элементы[ИмяПоляАктивизироватьПоУмолчанию];
	КонецЕсли;
	
	Если ЭлектроннаяПодписьСлужебныйКлиент.ИспользоватьСервисОблачнойПодписи() Тогда
		МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
		МодульСервисКриптографииDSSПодтверждениеКлиент.ПодтверждениеПриОткрытии(ЭтотОбъект, Отказ, Ложь, ОписаниеДанных);
	КонецЕсли;
	
	ПодключитьОбработчикОжидания("ЗаполнитьПрограммуШифрованияОбработчикОжидания", 0.1, Истина);
	
КонецПроцедуры

&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
	
	ОчиститьПеременныеФормы();
	
КонецПроцедуры

&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
	
	Если ВРег(ИмяСобытия) = ВРег("Запись_ПрограммыЭлектроннойПодписиИШифрования")
	 Или ВРег(ИмяСобытия) = ВРег("Запись_ПутиКПрограммамЭлектроннойПодписиИШифрованияНаСерверахLinux")
	 Или ВРег(ИмяСобытия) = ВРег("Запись_СертификатыКлючейЭлектроннойПодписиИШифрования") Тогда
		
		Если УказанНеизменяемыйНаборСертификатов Тогда
			ПодключитьОбработчикОжидания("ПерезаполнитьПрограммуШифрования", 0.1, Истина);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Если ВРег(ИмяСобытия) = ВРег("Запись_СертификатыКлючейЭлектроннойПодписиИШифрования") Тогда
		ПодключитьОбработчикОжидания("ПриИзмененииСпискаСертификатов", 0.1, Истина);
	КонецЕсли;
	
	Если ВРег(ИмяСобытия) = ВРег("ПодтверждениеВыполнитьОсновнуюОперацию") И Источник = УникальныйИдентификатор Тогда
		Если Параметр.Выполнено Тогда
			СвойстваОблачнойПодписи = ЭлектроннаяПодписьСлужебныйКлиент.ПолучитьСвойстваОблачнойПодписи(ОписаниеДанных);
			ОповещениеПриПодтверждении = СвойстваОблачнойПодписи.ОповещениеПриПодтверждении;
			Если ОповещениеПриПодтверждении = Неопределено Тогда
				ЗашифроватьДанные(Новый ОписаниеОповещения("ЗашифроватьЗавершение", ЭтотОбъект));
			Иначе
				ВыполнитьОбработкуОповещения(ОповещениеПриПодтверждении, ЭтотОбъект);
			КонецЕсли;
		Иначе
			ОбработатьОшибку(Новый ОписаниеОповещения("ЗашифроватьЗавершение", ЭтотОбъект),
				Новый Структура("ОписаниеОшибки", Параметр.Ошибка), Новый Структура);
		КонецЕсли;
		
	ИначеЕсли ВРег(ИмяСобытия) = ВРег("ПодтверждениеПодготовитьДанные") И Источник = УникальныйИдентификатор Тогда
		ЭлектроннаяПодписьСлужебныйКлиент.ПолучитьДанныеДляОблачнойПодписи(
			Параметр.ОбработчикСледующий, Параметр.КонтекстФормы, 
			Параметр.ОписаниеДанных, Параметр.Данные, Истина);
	
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиСобытийЭлементовШапкиФормы

&НаКлиенте
Процедура ПредставлениеДанныхНажатие(Элемент, СтандартнаяОбработка)
	
	ЭлектроннаяПодписьСлужебныйКлиент.ПредставлениеДанныхНажатие(ЭтотОбъект,
		Элемент, СтандартнаяОбработка, ТекущийСписокПредставлений);
	
КонецПроцедуры

&НаКлиенте
Процедура СертификатПриИзменении(Элемент)
	
	ЭлектроннаяПодписьСлужебныйКлиент.ПолучитьОтпечаткиСертификатовНаКлиенте(
		Новый ОписаниеОповещения("СертификатПриИзмененииЗавершение", ЭтотОбъект));
	
КонецПроцедуры

// Продолжение процедуры СертификатПриИзменении.
&НаКлиенте
Процедура СертификатПриИзмененииЗавершение(ОтпечаткиСертификатовНаКлиенте, Контекст) Экспорт
	
	СертификатПриИзмененииНаСервере(ОтпечаткиСертификатовНаКлиенте);
	
	Если ЭлектроннаяПодписьСлужебныйКлиент.ИспользоватьСервисОблачнойПодписи() Тогда
		МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
		МодульСервисКриптографииDSSПодтверждениеКлиент.ПроверитьНаОшибкуСертификата(ЭтотОбъект);
		МодульСервисКриптографииDSSПодтверждениеКлиент.ФильтроватьСписокСпособов(ЭтотОбъект);
		МодульСервисКриптографииDSSПодтверждениеКлиент.ПодтверждениеПриИзменении(ЭтотОбъект, Элементы.Сертификат, ОписаниеДанных, "");
	КонецЕсли;
	
	ЗаполнитьПрограммуШифрования();
	
КонецПроцедуры

&НаКлиенте
Процедура СертификатНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
	
	СтандартнаяОбработка = Ложь;
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ВыбранныйСертификат", Сертификат);
	ПараметрыФормы.Вставить("ДляШифрованияИРасшифровки", Истина);
	ПараметрыФормы.Вставить("ВыполнятьНаСервере", ВыполнятьНаСервере);
	ПараметрыФормы.Вставить("ОтображатьКомандыДобавления", Истина);
	
	ЭлектроннаяПодписьСлужебныйКлиент.ВыборСертификатаДляПодписанияИлиРасшифровки(ПараметрыФормы, Элемент);
	
КонецПроцедуры

&НаКлиенте
Процедура СертификатОткрытие(Элемент, СтандартнаяОбработка)
	
	СтандартнаяОбработка = Ложь;
	Если ЗначениеЗаполнено(Сертификат) Тогда
		ЭлектроннаяПодписьКлиент.ОткрытьСертификат(Сертификат);
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура СертификатОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
	
	СтандартнаяОбработка = Ложь;
	
	Сертификат = ВыбранноеЗначение;
	
	ЭлектроннаяПодписьСлужебныйКлиент.ПолучитьОтпечаткиСертификатовНаКлиенте(
		Новый ОписаниеОповещения("СертификатОбработкаВыбораЗавершение", ЭтотОбъект));
	
КонецПроцедуры

// Продолжение процедуры СертификатОбработкаВыбора.
&НаКлиенте
Процедура СертификатОбработкаВыбораЗавершение(ОтпечаткиСертификатовНаКлиенте, Контекст) Экспорт
	
	СертификатПриИзмененииНаСервере(ОтпечаткиСертификатовНаКлиенте);
	
	Если ЭлектроннаяПодписьСлужебныйКлиент.ИспользоватьСервисОблачнойПодписи() Тогда
		МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
		МодульСервисКриптографииDSSПодтверждениеКлиент.ПроверитьНаОшибкуСертификата(ЭтотОбъект);
		МодульСервисКриптографииDSSПодтверждениеКлиент.ФильтроватьСписокСпособов(ЭтотОбъект);
		МодульСервисКриптографииDSSПодтверждениеКлиент.ПодтверждениеПриИзменении(ЭтотОбъект, Элементы.Сертификат, ОписаниеДанных, "");
	КонецЕсли;
	
	ЗаполнитьПрограммуШифрования();
	
КонецПроцедуры

&НаКлиенте
Процедура СертификатАвтоПодбор(Элемент, Текст, ДанныеВыбора, Параметры, Ожидание, СтандартнаяОбработка)
	
	ЭлектроннаяПодписьСлужебныйКлиент.СертификатПодборИзСпискаВыбора(ЭтотОбъект, Текст, ДанныеВыбора, СтандартнаяОбработка);
	
КонецПроцедуры

&НаКлиенте
Процедура СертификатОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, Параметры, СтандартнаяОбработка)
	
	ЭлектроннаяПодписьСлужебныйКлиент.СертификатПодборИзСпискаВыбора(ЭтотОбъект, Текст, ДанныеВыбора, СтандартнаяОбработка);
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиСобытийЭлементовТаблицыФормыСертификатыШифрования

&НаКлиенте
Процедура СертификатыШифрованияОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
	
	Если ТипЗнч(ВыбранноеЗначение) <> Тип("Массив") Тогда
		Возврат;
	КонецЕсли;
	
	Для каждого Значение Из ВыбранноеЗначение Цикл
		Отбор = Новый Структура("Сертификат", Значение);
		Строки = СертификатыШифрования.НайтиСтроки(Отбор);
		Если Строки.Количество() > 0 Тогда
			Продолжить;
		КонецЕсли;
		СертификатыШифрования.Добавить().Сертификат = Значение;
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиКомандФормы

&НаКлиенте
Процедура Подобрать(Команда)
	
	ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.ПодборСертификатовДляШифрования",
		, Элементы.СертификатыШифрования);
	
КонецПроцедуры

&НаКлиенте
Процедура ОткрытьСертификат(Команда)
	
	Если Элементы.ВариантыШифрования.ТекущаяСтраница = Элементы.ПодборИзСправочника Тогда
		ТекущиеДанные = Элементы.СертификатыШифрования.ТекущиеДанные;
	Иначе
		ТекущиеДанные = Элементы.НаборСертификатов.ТекущиеДанные;
	КонецЕсли;
	
	Если ТекущиеДанные = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	Если Элементы.ВариантыШифрования.ТекущаяСтраница = Элементы.ПодборИзСправочника Тогда
		ЭлектроннаяПодписьКлиент.ОткрытьСертификат(ТекущиеДанные.Сертификат);
	Иначе
		ЭлектроннаяПодписьКлиент.ОткрытьСертификат(ТекущиеДанные.АдресДанных);
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура Зашифровать(Команда)
	
	Если Не УказанНеизменяемыйНаборСертификатов
	   И Не ПроверитьЗаполнение() Тогда
		
		Возврат;
	КонецЕсли;
	
	Если ЭлектроннаяПодписьСлужебныйКлиент.ЭтоОперацияОблачнойПодписи(ЭтотОбъект) Тогда
		МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
		Если МодульСервисКриптографииDSSПодтверждениеКлиент.ПроверкаПередВыполнениемОперации(ЭтотОбъект, "") Тогда 
			МодульСервисКриптографииDSSПодтверждениеКлиент.ВыполнитьНачальнуюОперациюСервиса(ЭтотОбъект, ОписаниеДанных, "");
			Элементы.ФормаЗашифровать.Доступность = Ложь;
		КонецЕсли;
		
	Иначе	
		Если Не Элементы.ФормаЗашифровать.Доступность Тогда
			Возврат;
		КонецЕсли;
	
		Элементы.ФормаЗашифровать.Доступность = Ложь;
		
		ЗашифроватьДанные(Новый ОписаниеОповещения("ЗашифроватьЗавершение", ЭтотОбъект));
	КонецЕсли;	
	
КонецПроцедуры

// Продолжение процедуры Зашифровать.
&НаКлиенте
Процедура ЗашифроватьЗавершение(Результат, Контекст) Экспорт
	
	Элементы.ФормаЗашифровать.Доступность = Истина;
	
	Если Результат = Истина И Открыта() Тогда
		Закрыть(Истина);
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

&НаСервере
Процедура ЗаполнитьСертификатыШифрованияИзНабора(ОписаниеНабораСертификатов)
	
	Если ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ОписаниеНабораСертификатов)) Тогда
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
			МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
			МодульУправлениеДоступом.ПроверитьЧтениеРазрешено(ОписаниеНабораСертификатов);
		КонецЕсли;
		Запрос = Новый Запрос;
		Запрос.УстановитьПараметр("Ссылка", ОписаниеНабораСертификатов);
		Запрос.Текст =
		"ВЫБРАТЬ
		|	СертификатыШифрования.Сертификат КАК Сертификат
		|ИЗ
		|	РегистрСведений.СертификатыШифрования КАК СертификатыШифрования
		|ГДЕ
		|	СертификатыШифрования.ЗашифрованныйОбъект = &Ссылка";
		УстановитьПривилегированныйРежим(Истина);
		Выборка = Запрос.Выполнить().Выбрать();
		УстановитьПривилегированныйРежим(Ложь);
		МассивСертификатов = Новый Массив;
		Пока Выборка.Следующий() Цикл
			МассивСертификатов.Добавить(Выборка.Сертификат.Получить());
		КонецЦикла;
	Иначе
		Если ТипЗнч(ОписаниеНабораСертификатов) = Тип("Строка") Тогда
			МассивСертификатов = ПолучитьИзВременногоХранилища(ОписаниеНабораСертификатов);
		Иначе
			МассивСертификатов = ОписаниеНабораСертификатов;
		КонецЕсли;
		ДобавленныеСертификаты = Новый Соответствие;
		Для Каждого ТекущийСертификат Из МассивСертификатов Цикл
			Если ТипЗнч(ТекущийСертификат) = Тип("СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования") Тогда
				Если ДобавленныеСертификаты.Получить(ТекущийСертификат) = Неопределено Тогда
					ДобавленныеСертификаты.Вставить(ТекущийСертификат, Истина);
					СертификатыШифрования.Добавить().Сертификат = ТекущийСертификат;
				КонецЕсли;
			Иначе
				СертификатыШифрования.Очистить();
				Прервать;
			КонецЕсли;
		КонецЦикла;
		Если СертификатыШифрования.Количество() > 0
		 Или МассивСертификатов.Количество() = 0 Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	ТаблицаСертификатов = Новый ТаблицаЗначений;
	ТаблицаСертификатов.Колонки.Добавить("Ссылка");
	ТаблицаСертификатов.Колонки.Добавить("Отпечаток");
	ТаблицаСертификатов.Колонки.Добавить("Представление");
	ТаблицаСертификатов.Колонки.Добавить("КомуВыдан");
	ТаблицаСертификатов.Колонки.Добавить("Данные");
	
	Ссылки = Новый Массив;
	Отпечатки = Новый Массив;
	Для Каждого ОписаниеСертификата Из МассивСертификатов Цикл
		НоваяСтрока = ТаблицаСертификатов.Добавить();
		Если ТипЗнч(ОписаниеСертификата) = Тип("ДвоичныеДанные") Тогда
			СертификатКриптографии = Новый СертификатКриптографии(ОписаниеСертификата);
			СвойстваСертификата = ЭлектроннаяПодпись.СвойстваСертификата(СертификатКриптографии);
			НоваяСтрока.Представление = СвойстваСертификата.Представление;
			НоваяСтрока.КомуВыдан     = СвойстваСертификата.КомуВыдан;
			НоваяСтрока.Отпечаток     = СвойстваСертификата.Отпечаток;
			НоваяСтрока.Данные        = ОписаниеСертификата;
			Отпечатки.Добавить(СвойстваСертификата.Отпечаток);
		Иначе
			НоваяСтрока.Ссылка = ОписаниеСертификата;
			Ссылки.Добавить(ОписаниеСертификата);
		КонецЕсли;
	КонецЦикла;
	ТаблицаСертификатов.Индексы.Добавить("Ссылка");
	ТаблицаСертификатов.Индексы.Добавить("Отпечаток");
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Ссылки", Ссылки);
	Запрос.УстановитьПараметр("Отпечатки", Отпечатки);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Сертификаты.Ссылка КАК Ссылка,
	|	Сертификаты.Отпечаток КАК Отпечаток,
	|	Сертификаты.Наименование КАК Представление,
	|	Сертификаты.ДанныеСертификата КАК ДанныеСертификата
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
	|ГДЕ
	|	(Сертификаты.Ссылка В (&Ссылки)
	|			ИЛИ Сертификаты.Отпечаток В (&Отпечатки))";
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Строки = ТаблицаСертификатов.НайтиСтроки(Новый Структура("Ссылка", Выборка.Ссылка));
		Для Каждого Строка Из Строки Цикл
			ДанныеСертификата = Выборка.ДанныеСертификата.Получить();
			Если ТипЗнч(ДанныеСертификата) <> Тип("ДвоичныеДанные") Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Данные сертификата ""%1"" не существуют в справочнике'"), Выборка.Представление);
			КонецЕсли;
			Попытка
				СертификатКриптографии = Новый СертификатКриптографии(ДанныеСертификата);
			Исключение
				ИнформацияОбОшибке = ИнформацияОбОшибке();
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Данные сертификата ""%1"" в справочнике некорректны по причине:
					           |%2'"),
					Выборка.Представление,
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
			КонецПопытки;
			СвойстваСертификата = ЭлектроннаяПодпись.СвойстваСертификата(СертификатКриптографии);
			Строка.Отпечаток     = Выборка.Отпечаток;
			Строка.Представление = Выборка.Представление;
			Строка.КомуВыдан     = СвойстваСертификата.КомуВыдан;
			Строка.Данные        = ДанныеСертификата;
		КонецЦикла;
		Строки = ТаблицаСертификатов.НайтиСтроки(Новый Структура("Отпечаток", Выборка.Отпечаток));
		Для Каждого Строка Из Строки Цикл
			Строка.Ссылка        = Выборка.Ссылка;
			Строка.Представление = Выборка.Представление;
		КонецЦикла;
	КонецЦикла;
	
	// Удаление дублей.
	ВсеОтпечатки = Новый Соответствие;
	Индекс = ТаблицаСертификатов.Количество() - 1;
	Пока Индекс >= 0 Цикл
		Строка = ТаблицаСертификатов[Индекс];
		Если ВсеОтпечатки.Получить(Строка.Отпечаток) = Неопределено Тогда
			ВсеОтпечатки.Вставить(Строка.Отпечаток, Истина);
		Иначе
			ТаблицаСертификатов.Удалить(Индекс);
		КонецЕсли;
		Индекс = Индекс - 1;
	КонецЦикла;
	
	Отбор = Новый Структура("Ссылка", Неопределено);
	ВсеСертификатыВСправочнике = ТаблицаСертификатов.НайтиСтроки(Отбор).Количество() = 0;
	
	Если ВсеСертификатыВСправочнике Тогда
		Для Каждого Строка Из ТаблицаСертификатов Цикл
			СертификатыШифрования.Добавить().Сертификат = Строка.Ссылка;
		КонецЦикла;
	Иначе
		СвойстваСертификатов = Новый Массив;
		Для Каждого Строка Из ТаблицаСертификатов Цикл
			НоваяСтрока = НаборСертификатов.Добавить();
			ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
			НоваяСтрока.АдресДанных = ПоместитьВоВременноеХранилище(Строка.Данные, УникальныйИдентификатор);
			Свойства = Новый Структура;
			Свойства.Вставить("Отпечаток",     Строка.Отпечаток);
			Свойства.Вставить("Представление", Строка.КомуВыдан);
			Свойства.Вставить("Сертификат",    Строка.Данные);
			СвойстваСертификатов.Добавить(Свойства);
		КонецЦикла;
		
		АдресСвойствСертификатов = ПоместитьВоВременноеХранилище(СвойстваСертификатов, УникальныйИдентификатор);
		Элементы.ВариантыШифрования.ТекущаяСтраница = Элементы.УказанныйНаборСертификатов;
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПерезаполнитьПрограммуШифрования()
	
	ЗаполнитьПрограммуШифрованияНаСервере();
	ЗаполнитьПрограммуШифрования();
	
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьПрограммуШифрованияНаСервере()
	
	СертификатПрограмма = Неопределено;
	ПрограммаАвто = Неопределено;
	ПрограммаАвтоНаСервере = Неопределено;
	
	Если НаборСертификатов.Количество() > 0 Тогда
		СертификатАдрес = НаборСертификатов[0].АдресДанных;
	Иначе
		Попытка
			ЗначенияРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(
				СертификатыШифрования[0].Сертификат, "Программа, ДанныеСертификата");
			
			Если ЗначениеЗаполнено(ЗначенияРеквизитов.Программа) Тогда
				СертификатПрограмма = ЗначенияРеквизитов.Программа;
				Возврат;
			КонецЕсли;
			
			ДвоичныеДанныеСертификата = ЗначенияРеквизитов.ДанныеСертификата.Получить();
			СертификатКриптографии = Новый СертификатКриптографии(ДвоичныеДанныеСертификата);
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось получить данные сертификата ""%1""
				           |из информационной базы по причине:
				           |%2'"),
				СертификатыШифрования[0].Сертификат,
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		КонецПопытки;
		СертификатАдрес = ПоместитьВоВременноеХранилище(ДвоичныеДанныеСертификата, УникальныйИдентификатор);
	КонецЕсли;
	
	Если Не ЭлектроннаяПодпись.СоздаватьЭлектронныеПодписиНаСервере() Тогда
		Возврат;
	КонецЕсли;
	
	ДвоичныеДанныеСертификата = ПолучитьИзВременногоХранилища(СертификатАдрес);
	СертификатКриптографии = Новый СертификатКриптографии(ДвоичныеДанныеСертификата);
	ТестовыеДанные = ТестовыеДвоичныеДанные();
	
	ПрограммаПоСертификатуРезультат = ЭлектроннаяПодписьСлужебный.ПрограммаПоСертификату(ДвоичныеДанныеСертификата,
		Неопределено);
	Если ЗначениеЗаполнено(ПрограммаПоСертификатуРезультат.Программа) Тогда
		ПрограммаАвтоНаСервере = ПрограммаПоСертификатуРезультат.Программа;
		Возврат;
	Иначе
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиНеУдалосьОпределитьПрограмму(
			ПрограммаПоСертификатуРезультат.Ошибка);
		СертификатНаСервереОписаниеОшибки = Новый Структура;
		СертификатНаСервереОписаниеОшибки.Вставить("ОписаниеОшибки", ТекстОшибки);
	КонецЕсли;
	
	ОписанияПрограмм = ЭлектроннаяПодпись.ОбщиеНастройки().ОписанияПрограмм;
	
	Если ЭлектроннаяПодписьСлужебныйКлиентСервер.ДоступныДополнительныеСвойстваСертификата() Тогда
		АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПредставлениеАлгоритмаПодписи(
				СертификатКриптографии.АлгоритмОткрытогоКлюча, Истина, Ложь);
	Иначе
		АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(ДвоичныеДанныеСертификата);
	КонецЕсли;
	
	Для Каждого ОписаниеПрограммы Из ОписанияПрограмм Цикл
		
		ПараметрыСоздания = ЭлектроннаяПодписьСлужебный.ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.Программа = ОписаниеПрограммы.Ссылка;
		ПараметрыСоздания.АлгоритмПодписи = АлгоритмПодписи;
		
		МенеджерКриптографии = ЭлектроннаяПодписьСлужебный.МенеджерКриптографии("Шифрование", ПараметрыСоздания);
		
		Если МенеджерКриптографии = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Попытка
			ЗашифрованныеТестовыеДанные = МенеджерКриптографии.Зашифровать(ТестовыеДанные, СертификатКриптографии);
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
		КонецПопытки;
		Если ИнформацияОбОшибке = Неопределено И ЗначениеЗаполнено(ЗашифрованныеТестовыеДанные) Тогда
			СертификатПрограмма = ОписаниеПрограммы.Ссылка;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

&НаСервереБезКонтекста
Функция ТестовыеДвоичныеДанные()
	
	Возврат БиблиотекаКартинок.СертификатКлюча.ПолучитьДвоичныеДанные();
	
КонецФункции

&НаКлиенте
Процедура ЗаполнитьПрограммуШифрованияОбработчикОжидания()
	ЗаполнитьПрограммуШифрования();
КонецПроцедуры

&НаКлиенте
Асинх Процедура ЗаполнитьПрограммуШифрования(Оповещение = Неопределено)
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение", Оповещение);
	
	Если ЗначениеЗаполнено(СертификатПрограмма) Тогда
		ЗаполнитьПрограммуШифрованияПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не ЭтоАдресВременногоХранилища(СертификатАдрес) Тогда
		ЗаполнитьПрограммуШифрованияПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	
	РезультатПрограммаПоСертификату = Ждать ЭлектроннаяПодписьСлужебныйКлиент.ПрограммаПоСертификату(
		СертификатАдрес, Неопределено, Неопределено, Истина);
	Если ЗначениеЗаполнено(РезультатПрограммаПоСертификату.Программа) Тогда
		ПрограммаАвто = РезультатПрограммаПоСертификату.Программа;
		ЗаполнитьПрограммуШифрованияПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	
	ДанныеСертификата = ПолучитьИзВременногоХранилища(СертификатАдрес);
	
	Контекст.Вставить("АлгоритмПодписи",
		ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(ДанныеСертификата));
		
	СертификатКриптографии = Новый СертификатКриптографии;
	Ждать СертификатКриптографии.ИнициализироватьАсинх(ДанныеСертификата);
		
	ОписанияПрограмм = ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ОписанияПрограмм;
	Контекст.Вставить("СертификатШифрования", СертификатКриптографии);
	Контекст.Вставить("ОписанияПрограмм", ОписанияПрограмм);
	Если ОписанияПрограмм.Количество() = 0 Тогда
		ЗаполнитьПрограммуШифрованияПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("ТестовыеДанные", ТестовыеДвоичныеДанные());
	Контекст.Вставить("Индекс", -1);
	ЗаполнитьПрограммуШифрованияЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЗаполнитьПрограммуШифрования.
//
// Параметры:
//   Контекст - Структура:
//     * ОписаниеПрограммы - Структура:
//      ** Ссылка - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//
&НаКлиенте
Процедура ЗаполнитьПрограммуШифрованияЦиклНачало(Контекст)
	
	Если Контекст.ОписанияПрограмм.Количество() <= Контекст.Индекс + 1 Тогда
		ЗаполнитьПрограммуШифрованияПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	Контекст.Индекс = Контекст.Индекс + 1;
	Контекст.Вставить("ОписаниеПрограммы", Контекст.ОписанияПрограмм[Контекст.Индекс]);
	
	Если Не Контекст.Свойство("АлгоритмПодписи") Тогда
		Контекст.Вставить("АлгоритмПодписи", "");
	КонецЕсли;
	
	ПараметрыСоздания = ЭлектроннаяПодписьСлужебныйКлиент.ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.Программа = Контекст.ОписаниеПрограммы.Ссылка;
	ПараметрыСоздания.ПоказатьОшибку = Ложь;
	ПараметрыСоздания.АлгоритмПодписи = Контекст.АлгоритмПодписи;
	
	ЭлектроннаяПодписьСлужебныйКлиент.СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
			"ЗаполнитьПрограммуШифрованияПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
		"Шифрование", ПараметрыСоздания);
	
КонецПроцедуры

// Продолжение процедуры ЗаполнитьПрограммуШифрования.
//
// Параметры:
//  МенеджерКриптографии - МенеджерКриптографии
//                       - Неопределено
//  Контекст - Структура:
//     * ОписаниеПрограммы - Структура:
//         ** Ссылка - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//
&НаКлиенте
Процедура ЗаполнитьПрограммуШифрованияПослеСозданияМенеджераКриптографии(МенеджерКриптографии, Контекст) Экспорт
	
	Если ТипЗнч(МенеджерКриптографии) <> Тип("МенеджерКриптографии") Тогда
		ЗаполнитьПрограммуШифрованияЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
		
	МенеджерКриптографии.НачатьШифрование(Новый ОписаниеОповещения(
			"ЗаполнитьПрограммуШифрованияПослеШифрования", ЭтотОбъект, Контекст,
			"ЗаполнитьПрограммуШифрованияПослеОшибкиШифрования", ЭтотОбъект),
		Контекст.ТестовыеДанные, Контекст.СертификатШифрования);
	
КонецПроцедуры

// Продолжение процедуры ЗаполнитьПрограммуШифрования.
&НаКлиенте
Процедура ЗаполнитьПрограммуШифрованияПослеОшибкиШифрования(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	ЗаполнитьПрограммуШифрованияЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЗаполнитьПрограммуШифрования.
//
// Параметры:
//  ЗашифрованныеДанные - ДвоичныеДанные
//                      - Неопределено
//  Контекст - Структура:
//     * ОписаниеПрограммы - Структура:
//         ** Ссылка - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//
&НаКлиенте
Процедура ЗаполнитьПрограммуШифрованияПослеШифрования(ЗашифрованныеДанные, Контекст) Экспорт
	
	Если Не ЗначениеЗаполнено(ЗашифрованныеДанные) Тогда
		ЗаполнитьПрограммуШифрованияЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	СертификатПрограмма = Контекст.ОписаниеПрограммы.Ссылка;
	ЗаполнитьПрограммуШифрованияПослеЦикла(Контекст);
	
КонецПроцедуры

// Продолжение процедуры СоздатьМенеджерКриптографии.
&НаКлиенте
Асинх Процедура ЗаполнитьПрограммуШифрованияПослеЦикла(Контекст)
	
	Если ЗначениеЗаполнено(Сертификат) И Не ЗначениеЗаполнено(СертификатПрограмма)
		И Не ЗначениеЗаполнено(ПрограммаАвто) Тогда
		Токен = Ждать ЭлектроннаяПодписьСлужебныйКлиент.ПолучитьТокенПоСертификату(Контекст.СертификатШифрования);
		Если Токен <> Неопределено Тогда
			ПрограммаАвто = Токен;
		КонецЕсли;
	КонецЕсли;
	
	Если Контекст.Оповещение <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение);
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПродолжитьОткрытие(Оповещение, ОбщиеВнутренниеДанные, КлиентскиеПараметры) Экспорт
	
	ОписаниеДанных             = КлиентскиеПараметры.ОписаниеДанных;
	ФормаОбъекта               = КлиентскиеПараметры.Форма;
	ТекущийСписокПредставлений = КлиентскиеПараметры.ТекущийСписокПредставлений;
	
	ВнутренниеДанные = ОбщиеВнутренниеДанные;
	Контекст = Новый Структура("Оповещение", Оповещение);
	Оповещение = Новый ОписаниеОповещения("ПродолжитьОткрытие", ЭтотОбъект);
	
	ЭлектроннаяПодписьСлужебныйКлиент.ПродолжитьОткрытиеНачало(Новый ОписаниеОповещения(
		"ПродолжитьОткрытиеПослеНачала", ЭтотОбъект, Контекст), ЭтотОбъект, КлиентскиеПараметры, Истина);
	
КонецПроцедуры

// Продолжение процедуры ПродолжитьОткрытие.
&НаКлиенте
Процедура ПродолжитьОткрытиеПослеНачала(Результат, Контекст) Экспорт
	
	Если Результат <> Истина Тогда
		ПродолжитьОткрытиеЗавершение(Контекст);
		Возврат;
	КонецЕсли;
	
	Если УказанНеизменяемыйНаборСертификатов Тогда
		ЗаполнитьПрограммуШифрования(Новый ОписаниеОповещения(
			"ПродолжитьОткрытиеПослеЗаполненияПрограммы", ЭтотОбъект, Контекст));
	Иначе
		ПродолжитьОткрытиеПослеЗаполненияПрограммы(Неопределено, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПродолжитьОткрытие.
&НаКлиенте
Процедура ПродолжитьОткрытиеПослеЗаполненияПрограммы(Результат, Контекст) Экспорт
	
	МодульСервисКриптографииDSSПодтверждениеКлиент = Неопределено;
	Если ЭлектроннаяПодписьСлужебныйКлиент.ИспользоватьСервисОблачнойПодписи() Тогда
		МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
	КонецЕсли;
	
	Если БезПодтверждения Тогда
		Если МодульСервисКриптографииDSSПодтверждениеКлиент <> Неопределено Тогда
			ТребуетПодтверждения = МодульСервисКриптографииDSSПодтверждениеКлиент.ОблачнаяПодписьТребуетПодтверждения(ЭтотОбъект);
			Если НЕ ТребуетПодтверждения Тогда
				ОбработкаПослеПредупреждения = Неопределено;
				ЗашифроватьДанные(Новый ОписаниеОповещения("ПродолжитьОткрытиеПослеШифрованияДанных", ЭтотОбъект, Контекст));
				Возврат;
			КонецЕсли;	
		Иначе	
			ОбработкаПослеПредупреждения = Неопределено;
			ЗашифроватьДанные(Новый ОписаниеОповещения("ПродолжитьОткрытиеПослеШифрованияДанных", ЭтотОбъект, Контекст));
			Возврат;
		КонецЕсли;	
	КонецЕсли;
	
	Открыть();
	
	Если МодульСервисКриптографииDSSПодтверждениеКлиент <> Неопределено Тогда
		Если МодульСервисКриптографииDSSПодтверждениеКлиент.ПроверкаВыполненияНачальнойОперации(ЭтотОбъект, БезПодтверждения) Тогда 
			МодульСервисКриптографииDSSПодтверждениеКлиент.ВыполнитьНачальнуюОперациюСервиса(ЭтотОбъект, ОписаниеДанных, "");
		КонецЕсли;
	КонецЕсли;
	
	ПродолжитьОткрытиеЗавершение(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПродолжитьОткрытие.
&НаКлиенте
Процедура ПродолжитьОткрытиеПослеШифрованияДанных(Результат, Контекст) Экспорт
	
	ПродолжитьОткрытиеЗавершение(Контекст, Результат = Истина);
	
КонецПроцедуры

// Продолжение процедуры ПродолжитьОткрытие.
&НаКлиенте
Процедура ПродолжитьОткрытиеЗавершение(Контекст, Результат = Неопределено)
	
	Если Не Открыта() Тогда
		ОчиститьПеременныеФормы();
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

&НаКлиенте
Процедура ОчиститьПеременныеФормы()
	
	ОписаниеДанных             = Неопределено;
	ФормаОбъекта               = Неопределено;
	ТекущийСписокПредставлений = Неопределено;
	
КонецПроцедуры

&НаКлиенте
Функция ПеременныеОчищены()
	
	Возврат ОписаниеДанных = Неопределено
		И ФормаОбъекта = Неопределено
		И ТекущийСписокПредставлений = Неопределено;
	
КонецФункции

// АПК:78-выкл: для безопасной передачи данных на клиенте между формами, не отправляя их на сервер.
&НаКлиенте
Процедура ВыполнитьШифрование(КлиентскиеПараметры, ОбработкаЗавершения) Экспорт
// АПК:78-вкл: для безопасной передачи данных на клиенте между формами, не отправляя их на сервер.
	
	ЭлектроннаяПодписьСлужебныйКлиент.ОбновитьФормуПередПовторнымИспользованием(ЭтотОбъект, КлиентскиеПараметры);
	
	ОписаниеДанных             = КлиентскиеПараметры.ОписаниеДанных;
	ФормаОбъекта               = КлиентскиеПараметры.Форма;
	ТекущийСписокПредставлений = КлиентскиеПараметры.ТекущийСписокПредставлений;
	
	ОбработкаПослеПредупреждения = ОбработкаЗавершения;
	
	Контекст = Новый Структура("ОбработкаЗавершения", ОбработкаЗавершения);
	ЗашифроватьДанные(Новый ОписаниеОповещения("ВыполнитьШифрованиеЗавершение", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьШифрование.
&НаКлиенте
Процедура ВыполнитьШифрованиеЗавершение(Результат, Контекст) Экспорт
	
	ВыполнитьОбработкуОповещения(Контекст.ОбработкаЗавершения, Результат);
	
КонецПроцедуры

&НаКлиенте
Процедура ПриИзмененииСпискаСертификатов()
	
	ЭлектроннаяПодписьСлужебныйКлиент.ПолучитьОтпечаткиСертификатовНаКлиенте(
		Новый ОписаниеОповещения("ПриИзмененииСпискаСертификатовЗавершение", ЭтотОбъект));
	
КонецПроцедуры

// Продолжение процедуры ПриИзмененииСпискаСертификатов.
&НаКлиенте
Процедура ПриИзмененииСпискаСертификатовЗавершение(ОтпечаткиСертификатовНаКлиенте, Контекст) Экспорт
	
	СертификатПриИзмененииНаСервере(ОтпечаткиСертификатовНаКлиенте, Истина);
	
КонецПроцедуры

&НаСервере
Процедура СертификатПриИзмененииНаСервере(ОтпечаткиСертификатовНаКлиенте, ПроверитьСсылку = Ложь)
	
	Если ПроверитьСсылку
	   И ЗначениеЗаполнено(Сертификат)
	   И ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Сертификат, "Ссылка") <> Сертификат Тогда
		
		Сертификат = Неопределено;
	КонецЕсли;
	
	ЭлектроннаяПодписьСлужебный.СертификатПриИзмененииНаСервере(ЭтотОбъект, ОтпечаткиСертификатовНаКлиенте, Истина);
	
	Если ЭлектроннаяПодписьСлужебный.ИспользоватьСервисОблачнойПодписи() Тогда
		МодульСервисКриптографииDSSПодтверждениеСервер = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSSПодтверждениеСервер");
		МодульСервисКриптографииDSSПодтверждениеСервер.ПодтверждениеПриИзмененииСертификата(ЭтотОбъект, ПолучитьОсновнойСертификат());
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Асинх Процедура ЗашифроватьДанные(Оповещение)
	
	Если ЭлектроннаяПодписьСлужебныйКлиент.ЭтоОперацияОблачнойПодписи(ЭтотОбъект) Тогда
		ЭлектроннаяПодписьСлужебныйКлиент.УстановитьСвойстваОблачнойПодписи(ОписаниеДанных, 
			Новый Структура("УчетнаяЗапись", 
				ЭлектроннаяПодписьСлужебныйКлиент.ПолучитьДанныеОблачнойПодписи(ЭтотОбъект, "НастройкиПользователя")));
	Иначе	
		ЭлектроннаяПодписьСлужебныйКлиент.УстановитьСвойстваОблачнойПодписи(ОписаниеДанных, Новый Структура("УчетнаяЗапись"));
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("ОшибкаНаКлиенте", Новый Структура);
	Контекст.Вставить("ОшибкаНаСервере", Новый Структура);
	
	Если ЗначениеЗаполнено(Сертификат) Тогда
		Если Не ЗначениеЗаполнено(СертификатПрограмма)
			И Не ЗначениеЗаполнено(ПрограммаАвто) И Не ЗначениеЗаполнено(ПрограммаАвтоНаСервере) Тогда
			Контекст.ОшибкаНаКлиенте.Вставить("ОписаниеОшибки",
				НСтр("ru = 'У выбранного личного сертификата не указано приложение для закрытого ключа и его не удалось определить автоматически.
				           |Выберите другой сертификат.'"));
			ОбработатьОшибку(Оповещение, Контекст.ОшибкаНаКлиенте, Контекст.ОшибкаНаСервере);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Контекст.Вставить("ИдентификаторФормы", УникальныйИдентификатор);
	Если ТипЗнч(ФормаОбъекта) = Тип("ФормаКлиентскогоПриложения") Тогда
		Контекст.ИдентификаторФормы = ФормаОбъекта.УникальныйИдентификатор;
	ИначеЕсли ТипЗнч(ФормаОбъекта) = Тип("УникальныйИдентификатор") Тогда
		Контекст.ИдентификаторФормы = ФормаОбъекта;
	КонецЕсли;
	
	Если НаборСертификатов.Количество() = 0 Тогда
		Ссылки = Новый Массив;
		ИсключитьЛичныйСертификат = Ложь;
		Если Элементы.Сертификат.Видимость И ЗначениеЗаполнено(Сертификат) Тогда
			Ссылки.Добавить(Сертификат);
			ИсключитьЛичныйСертификат = Истина;
		КонецЕсли;
		Для каждого Строка Из СертификатыШифрования Цикл
			Если Не ИсключитьЛичныйСертификат Или Строка.Сертификат <> Сертификат Тогда
				Ссылки.Добавить(Строка.Сертификат);
			КонецЕсли;
		КонецЦикла;
		ОписаниеДанных.Вставить("СертификатыШифрования", СвойстваСертификатов(Ссылки, Контекст.ИдентификаторФормы));
	Иначе
		ОписаниеДанных.Вставить("СертификатыШифрования", АдресСвойствСертификатов);
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОписаниеДанных",     ОписаниеДанных);
	ПараметрыВыполнения.Вставить("Форма",              ЭтотОбъект);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы", Контекст.ИдентификаторФормы);
	ПараметрыВыполнения.Вставить("СертификатАдрес",    СертификатАдрес); // Для определения программы автоматически.
	
	Контекст.Вставить("ПараметрыВыполнения", ПараметрыВыполнения);
	
	Если ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере()
	   И ВыполнятьНаСервере <> Ложь Тогда
		
		Если ЗначениеЗаполнено(СертификатНаСервереОписаниеОшибки) Тогда
			Результат = Новый Структура("Ошибка", СертификатНаСервереОписаниеОшибки);
			СертификатНаСервереОписаниеОшибки = Новый Структура;
			ЗашифроватьДанныеПослеВыполненияНаСторонеСервера(Результат, Контекст);
		Иначе
			// Попытка шифрования на сервере.
			ЭлектроннаяПодписьСлужебныйКлиент.ВыполнитьНаСтороне(Новый ОписаниеОповещения(
					"ЗашифроватьДанныеПослеВыполненияНаСторонеСервера", ЭтотОбъект, Контекст),
				"Шифрование", "НаСторонеСервера", Контекст.ПараметрыВыполнения);
		КонецЕсли;
	Иначе
		ЗашифроватьДанныеПослеВыполненияНаСторонеСервера(Неопределено, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЗашифроватьДанные.
&НаКлиенте
Асинх Процедура ЗашифроватьДанныеПослеВыполненияНаСторонеСервера(Результат, Контекст) Экспорт
	
	Если ПеременныеОчищены() Тогда
		Возврат;
	КонецЕсли;
	
	Если Результат <> Неопределено Тогда
		ЗашифроватьДанныеПослеВыполнения(Результат);
	КонецЕсли;
	
	Если Результат <> Неопределено И Не Результат.Свойство("Ошибка") Тогда
		ЗашифроватьДанныеПослеВыполненияНаСторонеКлиента(Новый Структура, Контекст);
	Иначе
		Если Результат <> Неопределено Тогда
			Контекст.ОшибкаНаСервере = Результат.Ошибка;
			Если ВыполнятьНаСервере = Истина Тогда
				ЗашифроватьДанныеПослеВыполненияНаСторонеКлиента(Новый Структура, Контекст);
				Возврат;
			КонецЕсли;
		КонецЕсли;
		
		// Попытка шифрования на клиенте.
		ЭлектроннаяПодписьСлужебныйКлиент.ВыполнитьНаСтороне(Новый ОписаниеОповещения(
				"ЗашифроватьДанныеПослеВыполненияНаСторонеКлиента", ЭтотОбъект, Контекст),
			"Шифрование", "НаСторонеКлиента", Контекст.ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЗашифроватьДанные.
&НаКлиенте
Процедура ЗашифроватьДанныеПослеВыполненияНаСторонеКлиента(Результат, Контекст) Экспорт
	
	Если ПеременныеОчищены() Тогда
		Возврат;
	КонецЕсли;
	
	ЗашифроватьДанныеПослеВыполнения(Результат);
	
	Если Результат.Свойство("Ошибка") Тогда
		Контекст.ОшибкаНаКлиенте = Результат.Ошибка;
		ОбработатьОшибку(Контекст.Оповещение, Контекст.ОшибкаНаКлиенте, Контекст.ОшибкаНаСервере);
		Возврат;
	КонецЕсли;
	
	Если Не ЗаписатьСертификатыШифрования(Контекст.ИдентификаторФормы, Контекст.ОшибкаНаКлиенте) Тогда
		ОбработатьОшибку(Контекст.Оповещение, Контекст.ОшибкаНаКлиенте, Контекст.ОшибкаНаСервере);
		Возврат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПредставлениеДанных)
	   И (Не ОписаниеДанных.Свойство("СообщитьОЗавершении")
	      Или ОписаниеДанных.СообщитьОЗавершении <> Ложь) Тогда
		
		ЭлектроннаяПодписьКлиент.ИнформироватьОШифрованииОбъекта(
			ЭлектроннаяПодписьСлужебныйКлиент.ПолноеПредставлениеДанных(ЭтотОбъект),
			ТекущийСписокПредставлений.Количество() > 1);
	КонецЕсли;
	
	Если ОписаниеДанных.Свойство("КонтекстОперации") Тогда
		ОписаниеДанных.КонтекстОперации = ЭтотОбъект;
	КонецЕсли;
	
	Если ОповеститьОбОкончанииСрокаДействия Тогда
		ПараметрыОткрытияФормы = Новый Структура("Сертификат", Сертификат);
		ДействиеПриНажатии = Новый ОписаниеОповещения("ОткрытьФормуОповещенияОНеобходимостиЗаменыСертификата",
			ЭлектроннаяПодписьСлужебныйКлиент, ПараметрыОткрытияФормы);
		
		ПоказатьОповещениеПользователя(
			НСтр("ru = 'Необходима замена сертификата'"), ДействиеПриНажатии, Сертификат,
			БиблиотекаКартинок.ДиалогВосклицание, СтатусОповещенияПользователя.Важное,
			Сертификат);
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Истина);
	
КонецПроцедуры

// Продолжение процедуры ЗашифроватьДанные.
&НаКлиенте
Процедура ЗашифроватьДанныеПослеВыполнения(Результат)
	
	Если Результат.Свойство("ЕстьОбработанныеЭлементыДанных") Тогда
		// После начала шифрования изменять сертификаты более недопустимо,
		// иначе набор данных будет обработан по-разному.
		Элементы.Сертификат.ТолькоПросмотр = Истина;
		Элементы.СертификатыШифрования.ТолькоПросмотр = Истина;
	КонецЕсли;
	
КонецПроцедуры

&НаСервереБезКонтекста
Функция СвойстваСертификатов(Знач Ссылки, Знач ИдентификаторФормы)
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Ссылки", Ссылки);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Сертификаты.Ссылка КАК Ссылка,
	|	Сертификаты.Наименование КАК Наименование,
	|	Сертификаты.Программа,
	|	Сертификаты.ДанныеСертификата
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
	|ГДЕ
	|	Сертификаты.Ссылка В(&Ссылки)";
	
	Выборка = Запрос.Выполнить().Выбрать();
	СвойстваСертификатов = Новый Массив;
	
	Пока Выборка.Следующий() Цикл
		
		ДанныеСертификата = Выборка.ДанныеСертификата.Получить();
		Если ТипЗнч(ДанныеСертификата) <> Тип("ДвоичныеДанные") Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Данные сертификата ""%1"" не существует в справочнике'"),
				Выборка.Наименование);
		КонецЕсли;
		
		Попытка
			СертификатКриптографии = Новый СертификатКриптографии(ДанныеСертификата);
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Данные сертификата ""%1"" в справочнике некорректны по причине:
				           |%2'"),
				Выборка.Наименование,
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		КонецПопытки;
		СвойстваСертификата = ЭлектроннаяПодпись.СвойстваСертификата(СертификатКриптографии);
		
		Свойства = Новый Структура;
		Свойства.Вставить("Отпечаток",     СвойстваСертификата.Отпечаток);
		Свойства.Вставить("Представление", СвойстваСертификата.КомуВыдан);
		Свойства.Вставить("Сертификат",    ДанныеСертификата);
		
		СвойстваСертификатов.Добавить(Свойства);
	КонецЦикла;
	
	Возврат ПоместитьВоВременноеХранилище(СвойстваСертификатов, ИдентификаторФормы);
	
КонецФункции


&НаКлиенте
Функция ЗаписатьСертификатыШифрования(ИдентификаторФормы, Ошибка)
	
	ОписаниеОбъектов = Новый Массив;
	Если ОписаниеДанных.Свойство("Данные") Тогда
		ДобавитьОписаниеОбъекта(ОписаниеОбъектов, ОписаниеДанных);
	Иначе
		Для Каждого ЭлементДанных Из ОписаниеДанных.НаборДанных Цикл
			ДобавитьОписаниеОбъекта(ОписаниеОбъектов, ЭлементДанных);
		КонецЦикла;
	КонецЕсли;
	
	АдресСертификатов = ОписаниеДанных.СертификатыШифрования;
	
	Ошибка = Новый Структура;
	ЗаписатьСертификатыШифрованияНаСервере(ОписаниеОбъектов, АдресСертификатов, ИдентификаторФормы, Ошибка);
	
	Возврат Не ЗначениеЗаполнено(Ошибка);
	
КонецФункции

// Возвращаемое значение:
//   Структура:
//     * Ссылка - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//
&НаКлиенте
Функция ОписаниеОбъекта(ЭлементДанных)
	
	ВерсияОбъекта = Неопределено;
	ЭлементДанных.Свойство("ВерсияОбъекта", ВерсияОбъекта);
	
	ОписаниеОбъекта = Новый Структура;
	ОписаниеОбъекта.Вставить("Ссылка", ЭлементДанных.Объект);
	ОписаниеОбъекта.Вставить("Версия", ВерсияОбъекта);
	
	Возврат ОписаниеОбъекта;
	
КонецФункции

&НаКлиенте
Процедура ДобавитьОписаниеОбъекта(ОписаниеОбъектов, ЭлементДанных)
	
	Если Не ЭлементДанных.Свойство("Объект") Тогда
		Возврат;
	КонецЕсли;
	
	ОписаниеОбъектов.Добавить(ОписаниеОбъекта(ЭлементДанных));
	
КонецПроцедуры

// Параметры:
//   ОписаниеОбъектов - Массив из см. ОписаниеОбъекта
//
&НаСервереБезКонтекста
Процедура ЗаписатьСертификатыШифрованияНаСервере(ОписаниеОбъектов, АдресСертификатов, ИдентификаторФормы, Ошибка)
	
	СвойстваСертификатов = ПолучитьИзВременногоХранилища(АдресСертификатов);
	
	НачатьТранзакцию();
	Попытка
		Для каждого ОписаниеОбъекта Из ОписаниеОбъектов Цикл
			ЭлектроннаяПодпись.ЗаписатьСертификатыШифрования(ОписаниеОбъекта.Ссылка,
				СвойстваСертификатов, ИдентификаторФормы, ОписаниеОбъекта.Версия);
		КонецЦикла;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Ошибка.Вставить("ОписаниеОшибки", НСтр("ru = 'Не удалось записать сертификаты шифрования по причине:'")
			+ Символы.ПС + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
	КонецПопытки;
	
КонецПроцедуры

&НаКлиенте
Процедура ОбработатьОшибку(Оповещение, ОшибкаНаКлиенте, ОшибкаНаСервере)
	
	Если ОписаниеДанных.Свойство("ПрекратитьВыполнение") Тогда
		
		Если Не ОписаниеДанных.Свойство("ОписаниеОшибки") Тогда
			ОписаниеДанных.Вставить("ОписаниеОшибки");
		КонецЕсли;
		
		ОписаниеДанных.ОписаниеОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбщееОписаниеОшибки(
			ОшибкаНаКлиенте, ОшибкаНаСервере, НСтр("ru = 'Не удалось зашифровать данные по причине:'"));
		
		Если Открыта() Тогда
			Закрыть(Ложь);
		Иначе
			ВыполнитьОбработкуОповещения(Оповещение, Ложь);
		КонецЕсли;
		
	Иначе
		
		Если Не Открыта() И ОбработкаПослеПредупреждения = Неопределено Тогда
			Открыть();
		КонецЕсли;
		
		ВсеСертификаты = Новый Массив;
		Если ЗначениеЗаполнено(Сертификат) Тогда
			ВсеСертификаты.Добавить(Сертификат);
		КонецЕсли;
		
		Если СертификатыШифрования.Количество() > 0 Тогда
			Для Каждого Строка Из СертификатыШифрования Цикл
				Если Не ЗначениеЗаполнено(Строка.Сертификат)
					Или ВсеСертификаты.Найти(Строка.Сертификат) <> Неопределено Тогда
					Продолжить;
				КонецЕсли;
				ВсеСертификаты.Добавить(Строка.Сертификат);
			КонецЦикла;
		ИначеЕсли НаборСертификатов.Количество() > 0 Тогда
			Для Каждого Строка Из НаборСертификатов Цикл
				Если Не ЗначениеЗаполнено(Строка.АдресДанных)
					Или ВсеСертификаты.Найти(Строка.АдресДанных) <> Неопределено Тогда
					Продолжить;
				КонецЕсли;
				ВсеСертификаты.Добавить(Строка.АдресДанных);
			КонецЦикла;
		КонецЕсли;

		ДополнительныеПараметры = Новый Структура("Сертификат", ВсеСертификаты);
		
		ЭлектроннаяПодписьСлужебныйКлиент.ПоказатьОшибкуОбращенияКПрограмме(
			НСтр("ru = 'Не удалось зашифровать данные'"), "",
			ОшибкаНаКлиенте, ОшибкаНаСервере, ДополнительныеПараметры, ОбработкаПослеПредупреждения);
		
		ВыполнитьОбработкуОповещения(Оповещение, Ложь);
		
	КонецЕсли;
	
КонецПроцедуры

&НаСервере
Функция ПолучитьОсновнойСертификат()
	
	Результат = Неопределено;
	Если УказанНеизменяемыйНаборСертификатов Тогда
		Если СертификатыШифрования.Количество() > 0 Тогда
			Результат = СертификатыШифрования[0].Сертификат;
		КонецЕсли;	
	Иначе
		Результат = Сертификат;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// СтандартныеПодсистемы.ЭлектроннаяПодписьСервисаDSS

&НаКлиенте
Процедура Подключаемый_ПодтверждениеОбработкаКоманды(Команда)
	
	МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
	МодульСервисКриптографииDSSПодтверждениеКлиент.ПодтверждениеОбработкаКоманды(ЭтотОбъект, Команда, ОписаниеДанных, "");
	
КонецПроцедуры

&НаКлиенте
Процедура Подключаемый_ПодтверждениеОбработкаНавигационнойСсылки(Элемент, НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка)

	МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
	МодульСервисКриптографииDSSПодтверждениеКлиент.ПодтверждениеОбработкаНавигационнойСсылки(ЭтотОбъект, Элемент, 
		НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка);
	
КонецПроцедуры

&НаКлиенте
Процедура Подключаемый_ПодтверждениеПриИзменении(Элемент)

	МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
	МодульСервисКриптографииDSSПодтверждениеКлиент.ПодтверждениеПриИзменении(ЭтотОбъект, Элемент, ОписаниеДанных, "");
	
КонецПроцедуры

&НаКлиенте
Процедура Подключаемый_ПодтверждениеОбработчикОжидания()
	
	МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
	МодульСервисКриптографииDSSПодтверждениеКлиент.ПодтверждениеОбработкаОжидания(ЭтотОбъект, ОписаниеДанных, "");

КонецПроцедуры

&НаКлиенте
Процедура Подключаемый_ПодтверждениеНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)

	МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
	МодульСервисКриптографииDSSПодтверждениеКлиент.ПодтверждениеНачалоВыбора(ЭтотОбъект, Элемент, ДанныеВыбора, СтандартнаяОбработка);
	
КонецПроцедуры

// Конец СтандартныеПодсистемы.ЭлектроннаяПодписьСервисаDSS

#КонецОбласти

Связанные материалы