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

#Область ПрограммныйИнтерфейс

// Возвращает текущую настройку использования электронных подписей.
//
// Возвращаемое значение:
//  Булево - если Истина, электронные подписи используются.
//
Функция ИспользоватьЭлектронныеПодписи() Экспорт
	
	Возврат ОбщиеНастройки().ИспользоватьЭлектронныеПодписи;
	
КонецФункции

// Возвращает текущую настройку использования шифрования.
//
// Возвращаемое значение:
//  Булево - если Истина, шифрование используется.
//
Функция ИспользоватьШифрование() Экспорт
	
	Возврат ОбщиеНастройки().ИспользоватьШифрование;
	
КонецФункции

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

// Возвращает текущую настройку создания электронных подписей на сервере.
// Настройка также предполагает шифрование и расшифровку на сервере.
//
// Возвращаемое значение:
//  Булево - если Истина, электронные подписи будут создаваться на сервере.
//
Функция СоздаватьЭлектронныеПодписиНаСервере() Экспорт
	
	Возврат ОбщиеНастройки().СоздаватьЭлектронныеПодписиНаСервере;
	
КонецФункции

// Проверяет, что разрешена работа с Интернет-сервисами электронной подписи из приложения.
// Параметры:
//  ПоказатьОшибку - Булево - вызвать исключение.
// 
// Возвращаемое значение:
//  Булево
//
Функция РазрешенДоступКИнтернетСервисам(ПоказатьОшибку = Ложь) Экспорт
	
	РазрешенДоступКИнтернетСервисам = ОбщегоНазначения.РазрешенДоступКИнтернетСервисам(ПоказатьОшибку);
	
	УстановитьПривилегированныйРежим(Истина);
	РазрешитьДоступКИнтернетСервисамЭлектроннойПодписи = Константы.РазрешитьДоступКИнтернетСервисамЭлектроннойПодписи.Получить();
	УстановитьПривилегированныйРежим(Ложь);
	
	РазрешенаЗагрузкаИзИнтернета = РазрешенДоступКИнтернетСервисам И РазрешитьДоступКИнтернетСервисамЭлектроннойПодписи;
	
	Если Не РазрешенаЗагрузкаИзИнтернета И ПоказатьОшибку Тогда
		ВызватьИсключение ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗапрещенДоступКИнтернетСервисамТекстСообщения();
	КонецЕсли;
	
	Возврат РазрешенаЗагрузкаИзИнтернета;
	
КонецФункции

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

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

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

			КонецЕсли;
			// Конец СтандартныеПодсистемы.МашиночитаемыеДоверенности
			
		КонецЦикла;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Удаляет подпись объекта и записывает его.
// 
// Параметры:
//  Объект - ОпределяемыйТип.ПодписанныйОбъект - по ссылке будет получен объект,
//               заблокирован, изменен, записан. Объект должен иметь реквизит ПодписанЭП.
//           Либо передать сразу объект указанного выше типа, тогда он
//           будет изменен без блокировки и без записи.
// 
//  ПорядковыйНомер      - Число - порядковый номер подписи.
//                       - Массив - значения указанного выше типа.
//
//  ИдентификаторФормы - УникальныйИдентификатор - идентификатор формы, используемый для блокировки,
//                       если передана ссылка на объект.
//
//  ВерсияОбъекта      - Строка - версия данных объекта, если передана ссылка на объект, используемая
//                       для блокировки объекта перед записью, с учетом того, что подписание
//                       выполняется на клиенте и за время подписания объект мог быть изменен.
//
//  ЗаписанныйОбъект   - Произвольный - объект, который был получен и записан, если передавалась ссылка.
//
Процедура УдалитьПодпись(Объект, ПорядковыйНомер, ИдентификаторФормы = Неопределено,
			ВерсияОбъекта = Неопределено, ЗаписанныйОбъект = Неопределено) Экспорт
	
	ПроверитьПараметрОбъект(Объект, "ЭлектроннаяПодпись.УдалитьПодпись");
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
		МодульУправлениеДоступом.ПроверитьИзменениеРазрешено(Объект);
	КонецЕсли;
	
	ЭтоСсылка = ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Объект));
	НачатьТранзакцию();
	Попытка
		Если ЭтоСсылка Тогда
			ЗаблокироватьДанныеДляРедактирования(Объект, ВерсияОбъекта, ИдентификаторФормы);
			ОбъектДанных = Объект.ПолучитьОбъект();
		Иначе
			ОбъектДанных = Объект;
		КонецЕсли;
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить(ОбъектДанных.Метаданные().ПолноеИмя());
		ЭлементБлокировки.УстановитьЗначение("Ссылка", ОбъектДанных.Ссылка);
		Блокировка.Заблокировать();
		
		СообщениеЖурналаРегистрации = "";
		
		УдалитьСтрокиПодписи(ОбъектДанных, ПорядковыйНомер, СообщениеЖурналаРегистрации);
		
		ОбновитьНумерациюПодписей(ОбъектДанных);
		
		Если ЭтоСсылка Тогда
			// Чтобы определить, что это запись с целью добавления/удаления подписи.
			ОбъектДанных.ДополнительныеСвойства.Вставить("ЗаписьПодписанногоОбъекта", Истина);
			Если ОбъектДанных.Модифицированность() Тогда
				ОбъектДанных.Записать();
			КонецЕсли;
			РазблокироватьДанныеДляРедактирования(Объект.Ссылка, ИдентификаторФормы);
			ЗаписанныйОбъект = ОбъектДанных;
		КонецЕсли;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Если ЗначениеЗаполнено(СообщениеЖурналаРегистрации) Тогда
			ЗаписьЖурналаРегистрации(
				НСтр("ru = 'Электронная подпись.Ошибка удаления подписи'", ОбщегоНазначения.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Информация,
				Объект.Метаданные(),
				Объект.Ссылка,
				СообщениеЖурналаРегистрации + "
				|
				|" + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		КонецЕсли;
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

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

КонецФункции

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

// Возвращает дату, извлеченную из двоичных данных подписи, или Неопределено.
//
// Параметры:
//  Подпись - ДвоичныеДанные - данные подписи из которых нужно извлечь дату.
//  ПривестиКЧасовомуПоясуСеанса - Булево - привести универсальное время к времени сеанса.
//
// Возвращаемое значение:
//  Дата - успешно извлеченная дата подписи.
//  Неопределено - не удалось извлечь дату из данных подписи.
//
Функция ДатаПодписания(Подпись, ПривестиКЧасовомуПоясуСеанса = Истина) Экспорт
	
	ДатаПодписания = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДатаПодписанияУниверсальная(Подпись);
	
	Если ДатаПодписания = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Если ПривестиКЧасовомуПоясуСеанса Тогда
		ДатаПодписания = МестноеВремя(ДатаПодписания, ЧасовойПоясСеанса());
	КонецЕсли;
	
	Возврат ДатаПодписания;
	
КонецФункции

// Возвращает ссылку на сертификат по его двоичным данным или отпечатку.
//
// Параметры:
//  Сертификат - СертификатКриптографии - сертификат.
//             - ДвоичныеДанные - двоичные данные сертификата.
//             - Строка - строка (28), отпечаток сертификата в формате Base64.
//             - Строка - адрес временного хранилища, содержащего двоичные данные сертификата.
//
// Возвращаемое значение:
//  СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//  Неопределено - сертификат не существует в справочнике.
//
Функция СсылкаНаСертификат(Знач Сертификат) Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
	|	Сертификаты.Ссылка КАК Ссылка
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
	|ГДЕ
	|	Сертификаты.Отпечаток = &Отпечаток";
	Запрос.УстановитьПараметр("Отпечаток", ОтпечатокСертификата(Сертификат));
	
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		Возврат Выборка.Ссылка;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

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

	Результат = ОтпечаткиСертификатов.ВыгрузитьКолонку("Ссылка");
	Возврат ОбщегоНазначенияКлиентСервер.СвернутьМассив(Результат);
	
КонецФункции

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

// Возвращает табличный документ, содержащий штамп визуализации электронной подписи.
//
// Параметры:
//  Подпись - см. ЭлектроннаяПодписьКлиентСервер.НовыеСвойстваПодписи
//  ДатаПодписи  - Дата -  дата подписания документа.
//  ТекстОтметки - Строка -  текст, выводящийся непосредственно под штампом и описывающий
//                          расположение подлинника документа.
//  ЛоготипОрганизации - Картинка - если не указан, то будет использована стандартная картинка.
//
// Возвращаемое значение:
//  ТабличныйДокумент - табличный документ, содержащий готовый штамп электронной подписи.
//
Функция ШтампВизуализацииЭлектроннойПодписи(Знач Подпись, Знач ДатаПодписи = Неопределено, 
	Знач ТекстОтметки = "", Знач ЛоготипОрганизации = Неопределено) Экспорт

	Если ТипЗнч(Подпись) = Тип("СертификатКриптографии") Тогда
		НоваяПодпись = ЭлектроннаяПодписьКлиентСервер.НовыеСвойстваПодписи();
		//@skip-check bsl-legacy-check-expression-type - для обратной совместимости
		НоваяПодпись.Сертификат = Подпись;
		НоваяПодпись.ДатаПодписи = ?(ДатаПодписи = Неопределено, Дата(1,1,1), ДатаПодписи);
		Подпись = НоваяПодпись;
	Иначе
		Подпись.ДатаПодписи = ?(ДатаПодписи = Неопределено, Подпись.ДатаПодписи, ДатаПодписи);
	КонецЕсли;
	
	Результат = ШтампыВизуализацииЭлектронныхПодписей(Неопределено, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Подпись),
		?(Не ПустаяСтрока(ТекстОтметки), ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТекстОтметки), Неопределено));
	Возврат Результат[0];
	
КонецФункции

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

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

		Сертификат = ?(ТипЗнч(Подпись.Сертификат) = Тип("СертификатКриптографии"), // для обратной совместимости
			Подпись.Сертификат, Новый СертификатКриптографии(Подпись.Сертификат));
		СвойстваСертификата = СвойстваСертификата(Сертификат);

		ПериодДействия = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ПериодДействияШаблон,
			Формат(СвойстваСертификата.ДатаНачала,    "ДЛФ=D"),
			Формат(СвойстваСертификата.ДатаОкончания, "ДЛФ=D"));
	
		ПараметрыШтампа = Новый Структура;
		ПараметрыШтампа.Вставить("ДатаПодписи", Подпись.ДатаПодписи);
		ПараметрыШтампа.Вставить("НомерСертификата", СтрЗаменить(СвойстваСертификата.СерийныйНомер, " ", ""));
		ПараметрыШтампа.Вставить("ВыдалСертификат", СвойстваСертификата.КемВыдан);
		ПараметрыШтампа.Вставить("ВладелецСертификата", СвойстваСертификата.КомуВыдан);
		ПараметрыШтампа.Вставить("СрокДействия", ПериодДействия);
		
		ПараметрыШтампа.Вставить("ТекстОтметки", ?(ТекстыОтметок <> Неопределено, ТекстыОтметок[Индекс], Неопределено));
		ПараметрыШтампа.Вставить("ЛоготипОрганизации", Неопределено);

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

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

КонецФункции

// Размещает штампы в переданном табличном документе.
//
// Параметры:
//  Документ        - ТабличныйДокумент - табличный документ, в который требуется добавить штампы.
//  ОписаниеШтампов - Массив из ТабличныйДокумент - штампы, полученные функцией
//                             ЭлектроннаяПодпись.ШтампВизуализацииЭлектроннойПодписи.
//                             Переданные штампы будут выведены в конец документа, либо в области для размещения 
//                             штампов, если они определены в макете табличного документа:
//                               а) имя области задано как "ШтампЭП" + порядковый номер штампа,
//                                  например: "ШтампЭП1" и т.д.
//                               б) область вывода штампа размером в две колонки и семь строк, с произвольной
//                                  шириной колонок.
//                             В таком случае штампы будут выведены в заданные области в порядке
//                             их следования в параметре ОписаниеШтампов.
//                  - Соответствие из КлючИЗначение - описывает места вывода штампов, где:
//                       * Ключ     - Строка - имя области, куда выводить штамп. Для такой области должна
//                                    быть установлена произвольная ширина колонок, 
//                                    отличная от ширины колонок остального документа.
//                       * Значение - ТабличныйДокумент - штамп, полученный функцией
//                                       ЭлектроннаяПодпись.ШтампВизуализацииЭлектроннойПодписи.
//  Размеры         - Структура - позволяет изменять размеры штампа, со свойствами:
//                       * ЛеваяКолонка  - Число - ширина левой колонки штампа, содержащей заголовки свойств.
//                                                 По умолчанию - 10.
//                       * ПраваяКолонка - Число - ширина правой колонки штампа, содержащей значения свойств.
//                                                 По умолчанию - 30.
//
Процедура ДобавитьШтампыВТабличныйДокумент(Документ, ОписаниеШтампов, Размеры = Неопределено) Экспорт
	
	Если Размеры = Неопределено Тогда
		Размеры = Новый Структура;
		Размеры.Вставить("ЛеваяКолонка", 10);
		Размеры.Вставить("ПраваяКолонка", 30);
	КонецЕсли;
	
	Если ТипЗнч(ОписаниеШтампов) = Тип("Массив") Тогда
		
		ИндексШтампа = 1; КоличествоШтампов = ОписаниеШтампов.Количество();
		
		ШиринаКолонокШтампа = 3 + Размеры.ЛеваяКолонка + Размеры.ПраваяКолонка;
		
		КоличествоШтамповПоШирине = Неопределено;
		НомерШтампаВСтроке = 0; ШиринаСтрокиШтампов = 0; ШиринаТаблицы = 0;
		
		Для Каждого Штамп Из ОписаниеШтампов Цикл
			ИмяОбласти = "ШтампЭП" + Строка(ИндексШтампа);
			ОбластьНайдена = Ложь;
			Для Каждого ОчереднаяОбласть Из Документ.Области Цикл
				Если СтрНачинаетсяС(ОчереднаяОбласть.Имя, ИмяОбласти) Тогда
					ОбластьНайдена = Истина;
					ИмяОбласти = ОчереднаяОбласть.Имя;
					Прервать;
				КонецЕсли;
			КонецЦикла;
			
			Если ОбластьНайдена Тогда
				ОбластьШтампа = Документ.Области[ИмяОбласти];
				Документ.ВставитьОбласть(Штамп.Области.Штамп, ОбластьШтампа,, Истина);
				Документ.Область(ОбластьШтампа.Верх, ОбластьШтампа.Лево, ОбластьШтампа.Верх, ОбластьШтампа.Лево).ШиринаКолонки = Размеры.ЛеваяКолонка;
				Документ.Область(ОбластьШтампа.Верх, ОбластьШтампа.Право, ОбластьШтампа.Верх, ОбластьШтампа.Право).ШиринаКолонки = Размеры.ПраваяКолонка;
				Документ.Область(ОбластьШтампа.Верх, , ОбластьШтампа.Низ).ВысотаСтроки = 0;
				Документ.Область(ОбластьШтампа.Верх, , ОбластьШтампа.Низ).АвтоВысотаСтроки = Истина;
			Иначе
				НомерШтампаВСтроке = НомерШтампаВСтроке + 1;
				
				ШиринаШтампа = Штамп.Области.Штамп.Право;
				ШтампВерх = Штамп.Области.Штамп.Верх;
				ШтампНиз = Штамп.Области.Штамп.Низ;
				ВысотаШтампа = ШтампНиз - ШтампВерх;
				
				Если НомерШтампаВСтроке = 1 Или НомерШтампаВСтроке > КоличествоШтамповПоШирине Тогда
					
					Если КоличествоШтамповПоШирине = Неопределено Тогда
						
						Для ШиринаТаблицы = 1 По Документ.ШиринаТаблицы Цикл
							
							Область = Документ.Область(, ШиринаТаблицы,, ШиринаТаблицы);
							ШиринаСтрокиШтампов = ШиринаСтрокиШтампов + Область.ШиринаКолонки;
							Если Область.КонецСтраницы Тогда
								Прервать;
							КонецЕсли;
							
							Если ШиринаТаблицы = Документ.ШиринаТаблицы Тогда
								
								ШиринаСтрокиШтампов = 0;
								ВысотаТаблицы = Мин(Документ.ВысотаТаблицы, 100);
								
								Для НомерКолонкиСКонца = 1 По ШиринаТаблицы Цикл
									
									НомерКолонки = ШиринаТаблицы - НомерКолонкиСКонца + 1;
									
									Для НомерСтрокиСКонца = 1 По ВысотаТаблицы Цикл
										
										НомерСтроки = Документ.ВысотаТаблицы - НомерСтрокиСКонца + 1;
										
										ОбластьЯчейки = Документ.Область(НомерСтроки, НомерКолонки);
										
										Если ПустаяСтрока(ОбластьЯчейки.Текст)
											И ОбластьЯчейки.Лево = НомерКолонки
											И ОбластьЯчейки.Верх = НомерСтроки
											И ОбластьЯчейки.ГраницаСправа.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии
											И ОбластьЯчейки.ГраницаСнизу.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии
											И ОбластьЯчейки.ГраницаСверху.ТипЛинии = ТипЛинииЯчейкиТабличногоДокумента.НетЛинии
											Тогда
											Продолжить;
										КонецЕсли;
										
										ТабличныйДокумент = Новый ТабличныйДокумент;
										Область = Документ.ПолучитьОбласть(НомерСтроки, 1, НомерСтроки, НомерКолонки);
										ТабличныйДокумент.Вывести(Область);
										
										Для НомерКолонкиТабличногоДокумента = 1 По НомерКолонки Цикл
											Область = ТабличныйДокумент.Область(1, НомерКолонкиТабличногоДокумента, 1,
												НомерКолонкиТабличногоДокумента);
											ШиринаСтрокиШтампов = ШиринаСтрокиШтампов + Область.ШиринаКолонки;
										КонецЦикла;
										
										Прервать;
									КонецЦикла;
									
									Если ШиринаСтрокиШтампов <> 0 Тогда
										Прервать;
									КонецЕсли;
								КонецЦикла;
								
								Прервать;
							КонецЕсли;
						КонецЦикла;
						КоличествоШтамповПоШирине = Макс(1, Цел(ШиринаСтрокиШтампов/ШиринаКолонокШтампа));
					КонецЕсли;
						
					ШиринаНачало = 1; НомерШтампаВСтроке = 1;
					
					ОбластиДляПроверкиПоВысоте = Новый Массив;
					ОбластиДляПроверкиПоВысоте.Добавить(Штамп.ПолучитьОбласть("Отступ"));
					ОбластиДляПроверкиПоВысоте.Добавить(Штамп.ПолучитьОбласть("ОбластьСтрокШтамп"));
					Если Не ОбщегоНазначения.ПроверитьВыводТабличногоДокумента(Документ, ОбластиДляПроверкиПоВысоте, Истина) Тогда
						Документ.ВывестиГоризонтальныйРазделительСтраниц();
					КонецЕсли;
					
					Документ.Вывести(Штамп.ПолучитьОбласть("Отступ"));
					
					ВысотаНачало = Документ.ВысотаТаблицы;
					ВысотаКонец = Документ.ВысотаТаблицы + ВысотаШтампа;
					
					Документ.Область(ВысотаНачало, ШиринаНачало, ВысотаКонец, ШиринаТаблицы).Разъединить();
					// Формат строк, чтобы изменение ширины колонок не повлияло на остальной документ.
					Документ.Область(ВысотаНачало, , ВысотаКонец).СоздатьФорматСтрок();
					
					ОстатокШирины = ШиринаСтрокиШтампов;
					
				Иначе
					
					ВысотаКонец = ВысотаНачало + ВысотаШтампа;
					
				КонецЕсли;
				
				ШиринаКонец = ШиринаНачало - 1 + ШиринаШтампа;
				
				// Вставка в разъединенные области область из макета штампа.
				ИсходнаяОбласть = Штамп.Область(ШтампВерх, 1, ШтампНиз, ШиринаШтампа);
				ОбластьПриемник = Документ.Область(ВысотаНачало, ШиринаНачало, ВысотаКонец, ШиринаКонец);
				Документ.ВставитьОбласть(ИсходнаяОбласть, ОбластьПриемник, , Истина);
				
				Для Каждого ОчереднаяОбласть Из Документ.Области Цикл
					ИмяОбласти = ОчереднаяОбласть.Имя; 
					Если СтрНачинаетсяС(ИмяОбласти, "Документ") И СтрНайти(ИмяОбласти, "Устарела") = 0 Тогда
						ОчереднаяОбласть.Имя = ИмяОбласти+"_Устарела_"+ИндексШтампа;
						Документ.Область().Имя = ИмяОбласти;
						Прервать;
					КонецЕсли;
				КонецЦикла;
				
				Документ.Области.ШтампЛеваяКолонка.ШиринаКолонки  = Размеры.ЛеваяКолонка;
				Документ.Области.ШтампПраваяКолонка.ШиринаКолонки = Размеры.ПраваяКолонка;
				Документ.Области.ОтступШтампа.ШиринаКолонки       = 3;
					
				ШиринаНачало = ШиринаКонец + 1;
				
				Если ОстатокШирины > ШиринаКолонокШтампа Или ИндексШтампа = КоличествоШтампов Тогда
					
					ОстатокШирины = ОстатокШирины - ШиринаКолонокШтампа;
					
					Если ОстатокШирины < ШиринаКолонокШтампа Или ИндексШтампа = КоличествоШтампов Тогда
						Если ШиринаНачало < ШиринаТаблицы Тогда
							Документ.Область(ВысотаНачало, ШиринаНачало, ВысотаКонец, ШиринаТаблицы).ШиринаКолонки = 0;
						КонецЕсли;
						Если ОстатокШирины > 0 Тогда
							Документ.Область(ВысотаНачало, ШиринаНачало, ВысотаКонец, ШиринаНачало).ШиринаКолонки = ОстатокШирины;
						КонецЕсли;
					КонецЕсли;
				КонецЕсли;
			КонецЕсли;
			
			ИндексШтампа = ИндексШтампа + 1;
		КонецЦикла;

	Иначе
		Для Каждого ОписаниеШтампа Из ОписаниеШтампов Цикл
			ИмяОбласти = ОписаниеШтампа.Ключ;
			Штамп      = ОписаниеШтампа.Значение;
			ОбластьНайдена = Документ.Области.Найти(ИмяОбласти) <> Неопределено;
			Если ОбластьНайдена Тогда
				Документ.ВставитьОбласть(Штамп.Области.Штамп, Документ.Области[ИмяОбласти],, Истина);
				Документ.Области.ШтампЛеваяКолонка.ШиринаКолонки  = Размеры.ЛеваяКолонка;
				Документ.Области.ШтампПраваяКолонка.ШиринаКолонки = Размеры.ПраваяКолонка;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

// См. ЭлектроннаяПодписьКлиент.ПредставлениеСертификата.
Функция ПредставлениеСертификата(Сертификат) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ПредставлениеСертификата(Сертификат, ЭлектроннаяПодписьСлужебный.РазницаСУниверсальнымВременем());
	
КонецФункции

// См. ЭлектроннаяПодписьКлиент.ПредставлениеСубъекта.
Функция ПредставлениеСубъекта(Сертификат) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ПредставлениеСубъекта(Сертификат);
	
КонецФункции

// См. ЭлектроннаяПодписьКлиент.ПредставлениеИздателя.
Функция ПредставлениеИздателя(Сертификат) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ПредставлениеИздателя(Сертификат);
	
КонецФункции

// Возвращает основные свойства сертификата.
//
// Параметры:
//   Сертификат - СертификатКриптографии - сертификат криптографии.
//              - ДвоичныеДанные - двоичные данные сертификата в кодировке DER.
//
// Возвращаемое значение:
//   Структура:
//    * Отпечаток      - Строка - отпечаток сертификата в формате строки Base64.
//    * СерийныйНомер  - ДвоичныеДанные - свойство сертификата СерийныйНомер.
//    * Представление  - см. ЭлектроннаяПодписьКлиент.ПредставлениеСертификата.
//    * КомуВыдан      - см. ЭлектроннаяПодписьКлиент.ПредставлениеСубъекта.
//    * КемВыдан       - см. ЭлектроннаяПодписьКлиент.ПредставлениеИздателя.
//    * ДатаНачала     - Дата   - свойство сертификата ДатаНачала в часовом поясе сеанса.
//    * ДатаОкончания  - Дата   - свойство сертификата ДатаОкончания в часовом поясе сеанса.
//    * ДатаНачалаЗакрытогоКлюча     - Дата   - свойство сертификата, указанное в OID 2.5.29.16 в часовом поясе сеанса.
//    * ДатаОкончанияЗакрытогоКлюча  - Дата   - свойство сертификата, указанное в OID 2.5.29.16 в часовом поясе сеанса.
//    * ДействителенДо - Дата - минимальная дата из ДатаОкончания и ДатаОкончанияЗакрытогоКлюча (если указана в сертификате).
//    * Назначение     - Строка - описание расширенного свойства сертификата EKU.
//    * Подписание     - Булево - свойство сертификата ИспользоватьДляПодписи.
//    * Шифрование     - Булево - свойство сертификата ИспользоватьДляШифрования.
//        На платформе 8.3.27 и выше структура содержит свойства:
//    * ИдентификаторКлючаУдостоверяющегоЦентра - Строка - идентификатор ключа издателя.
//    * АлгоритмПодписи - Строка - OID алгоритма подписи сертификата.
//    * АлгоритмОткрытогоКлюча - Строка - OID алгоритма открытого ключа сертификата.
//    * АдресаСписковОтзыва - Массив из Строка
//
Функция СвойстваСертификата(Сертификат) Экспорт
	
	ДанныеСертификата = Сертификат;
	Если ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда
		ДвоичныеДанныеСертификата = Сертификат.Выгрузить();
	ИначеЕсли ТипЗнч(Сертификат) = Тип("ФиксированнаяСтруктура") Тогда
		ДвоичныеДанныеСертификата = Сертификат.Сертификат;
	ИначеЕсли ТипЗнч(Сертификат) = Тип("ДвоичныеДанные") Тогда
		ДвоичныеДанныеСертификата = Сертификат;
		ДанныеСертификата = Новый СертификатКриптографии(Сертификат);
	Иначе
		ДвоичныеДанныеСертификата = Неопределено;
	КонецЕсли;
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваСертификата(
		ДанныеСертификата, ЭлектроннаяПодписьСлужебный.РазницаСУниверсальнымВременем(), ДвоичныеДанныеСертификата);
	
КонецФункции

// См. ЭлектроннаяПодписьКлиент.СвойстваСубъектаСертификата.
Функция СвойстваСубъектаСертификата(Сертификат) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваСубъектаСертификата(Сертификат);
	
КонецФункции

// См. ЭлектроннаяПодписьКлиент.СвойстваИздателяСертификата.
Функция СвойстваИздателяСертификата(Сертификат) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваИздателяСертификата(Сертификат);
	
КонецФункции

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

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

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

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

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

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

		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='Не прошел проверку сертификат полученной метки времени: %1
					 |%2'"), ОписаниеОшибки, СведенияОСертификате);

		ВызватьИсключение ОписаниеОшибки;
	КонецЕсли;
	
	Результат.Успех = Истина;
	Возврат Результат;
	
КонецФункции

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

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

// Извлекает сертификат из двоичных данных подписи.
// 
// Параметры:
//  Подпись - ДвоичныеДанные - результат подписания
// 
// Возвращаемое значение:
//   ДвоичныеДанные - двоичные данные сертификата.
//   Неопределено - подпись не содержит сертификатов криптографии.
//
Функция СертификатИзДвоичныхДанныхПодписи(Подпись) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебный.СертификатИзДвоичныхДанныхПодписи(Подпись);
	
КонецФункции

#Область ДляВызоваИзДругихПодсистем

// Следующие процедуры и функции предназначены для интеграции с 1С:Библиотека электронных документов
// и 1С:Библиотека регламентированной отчетности.

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

// Извлекает свойства подписи из данных подписи. Если не удалось извлечь все свойства с помощью менеджера криптографии, 
// возвращается часть свойств, которые удалось прочитать из двоичных данных.
//
// Параметры:
//   Подпись - ДвоичныеДанные - данные подписи в кодировке DER.
//   ПрочитатьСертификаты - Булево - (по умолчанию Истина), если Ложь, свойства Сертификат, Отпечаток,
//                                   КомуВыданСертификат, Сертификаты не будут заполнены.
//
// Возвращаемое значение:
//   Структура:
//       * Успех       - Булево, Неопределено - Неопределено, если не удалось прочитать все свойства с помощью менеджера
//                                              криптографии.
//       * ТекстОшибки - Строка - заполнена, если Успех = Ложь или Неопределено
//       * ТипПодписи  - ПеречислениеСсылка.ТипыПодписиКриптографии
//       * СрокДействияПоследнейМеткиВремени - Дата, Неопределено - заполняется только с помощью менеджера криптографии.
//       * ДатаПодписиИзМетки - Дата, Неопределено - самый ранний штамп времени: CADES-T, если его нет, но есть другие штампы,
//               дата заполняется только с помощью менеджера криптографии.
//       * НеподтвержденнаяДатаПодписи - Дата - неподтвержденная дата подписи.
//                                     - Неопределено - неподтвержденная дата подписи отсутствует в данных подписи.
//       * Сертификат  - ДвоичныеДанные - сертификат для проверки подписи.
//       * Отпечаток           - Строка - отпечаток сертификата в формате строки Base64.
//       * КомуВыданСертификат - Строка - представление субъекта, полученное из двоичных данных сертификата. 
//       * Сертификаты - Массив из ДвоичныеДанные - сертификаты для проверки подписи.
//
Функция СвойстваПодписи(Подпись, ПрочитатьСертификаты = Истина) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебный.СвойстваПодписи(Подпись, ПрочитатьСертификаты)
	
КонецФункции

// Выполняет проверку установленных программ. Возвращает только установленные программы.
// 
// Параметры:
//  ПараметрыПроверки - Неопределено, Структура:
//   * ПроверяемыеПрограммы - Неопределено - (по умолчанию) возвращаются все установленные программы.
//                          - Булево - см. ЭлектроннаяПодписьКлиентСерверЛокализация.АктуальныеАлгоритмыПрограмм
//                          - ДвоичныеДанные - данные подписи или сертификата, для проверки наличия подходящих программ.
//                          - Строка - адрес во временном хранилище данных подписи или сертификата,
//                               для проверки наличия подходящих программ.
//                          - Массив - со значениями, как возвращает функция ЭлектроннаяПодпись.НовоеОписаниеПрограммы.
//  Возвращаемое значение:
//    Структура:
//     * ПроверкаВыполнена - Булево - Истина, если проверка выполнена на компьютере, получены установленные криптопровайдеры.
//                 если Ложь, то будет заполнена Ошибка.
//     * Ошибка - Строка - текст ошибки.
//     * Программы - Массив из Структура:
//        ** ИмяПрограммы  - Строка  - имя криптопровайдера, например "Infotecs GOST 2012/512 Cryptographic Service Provider"
//        ** ТипПрограммы  - Число  - тип криптопровайдера, например, 77
//        ** Имя           - Строка  - представление программы для установки, из списка поставляемых,
//             например НСтр("ru = 'ViPNet CSP'")
//        ** Версия        - Строка - версия библиотеки
//        ** Лицензия      - Булево - есть лицензия
//     * ВозможенКонфликт - Булево - установлено несколько программ криптографии, между
//             которыми возможен конфликт.
//
Функция ПроверитьУстановкуПрограммКриптографии(ПараметрыПроверки = Неопределено) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("ПроверяемыеПрограммы", Неопределено);
	Контекст.Вставить("РасширенноеОписание", Ложь);
	Контекст.Вставить("АлгоритмыПодписи", Новый Массив);
	Контекст.Вставить("ТипДанных", Неопределено);
	Контекст.Вставить("ЭтоСервер", Истина);
	
	Если ТипЗнч(ПараметрыПроверки) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Контекст, ПараметрыПроверки);
	КонецЕсли;
	
	Если Контекст.ПроверяемыеПрограммы <> Неопределено Тогда
		Если Контекст.ПроверяемыеПрограммы = Истина Тогда
			Контекст.ПроверяемыеПрограммы = Неопределено;
			Контекст.АлгоритмыПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АктуальныеАлгоритмыПрограмм();
			Контекст.ТипДанных = "Сертификат";
		ИначеЕсли ТипЗнч(Контекст.ПроверяемыеПрограммы) = Тип("ДвоичныеДанные")
			Или ТипЗнч(Контекст.ПроверяемыеПрограммы) = Тип("Строка") Тогда
			ДвоичныеДанные = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДвоичныеДанныеИзДанных(
				Контекст.ПроверяемыеПрограммы, "ЭлектроннаяПодпись.ПроверитьУстановкуПрограммКриптографии");
			Контекст.ПроверяемыеПрограммы = Неопределено;
			Контекст.ТипДанных = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОпределитьТипДанных(ДвоичныеДанные);
			Если Контекст.ТипДанных = "Сертификат" Тогда
				АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(ДвоичныеДанные);
			ИначеЕсли Контекст.ТипДанных = "Подпись" Тогда
				АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(ДвоичныеДанные);
			Иначе
				ВызватьИсключение НСтр("ru = 'Данные для поиска приложения криптографии не являются сертификатом или подписью.'");
			КонецЕсли;
			Контекст.АлгоритмыПодписи.Добавить(АлгоритмПодписи);
		КонецЕсли;
	КонецЕсли;
	
	Результат = ЭлектроннаяПодписьСлужебныйПовтИсп.УстановленныеКриптопровайдеры();
	
	РезультатПроверки = Новый Структура("Ошибка, ПроверкаВыполнена");
	РезультатПроверки.Вставить("Программы", Новый Массив);
	РезультатПроверки.Вставить("ВозможенКонфликт", Ложь);
	ЗаполнитьЗначенияСвойств(РезультатПроверки, Результат);
	Если Не РезультатПроверки.ПроверкаВыполнена Тогда
		Возврат РезультатПроверки;
	КонецЕсли;
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбработатьРезультатПроверкиПрограмм(Результат.Криптопровайдеры,
		РезультатПроверки.Программы, РезультатПроверки.ВозможенКонфликт, Контекст);
		
	Возврат РезультатПроверки;
	
КонецФункции

// Проверяет действительность подписи и сертификата.
// Только для работы через средства платформы (МенеджерКриптографии).
//
// Параметры:
//   МенеджерКриптографии - Неопределено - получить менеджер криптографии для проверки
//                          электронных подписей, как настроил администратор.
//                        - МенеджерКриптографии - использовать указанный менеджер криптографии.
//
//   ИсходныеДанные       - ДвоичныеДанные - двоичные данные, которые были подписаны.
//                        - Строка         - адрес временного хранилища, содержащего двоичные данные.
//                        - Строка         - полное имя файла, содержащего двоичные данные,
//                                           которые были подписаны.
//                        - Структура:
//                           * КонвертXML       - Строка - подписанный КонвертXML,
//                                                         смотри также функцию КонвертXML.
//                           * ПараметрыXMLDSig - см. ЭлектроннаяПодпись.ПараметрыXMLDSig
//                        - Структура:
//                           * ПараметрыCMS - см. ЭлектроннаяПодпись.ПараметрыCMS
//                           * Данные  - Строка - произвольная строка для подписания,
//                                     - ДвоичныеДанные - двоичные данные для подписания.
//
//   Подпись              - ДвоичныеДанные - двоичные данные электронной подписи.
//                        - Строка         - адрес временного хранилища, содержащего двоичные данные.
//                        - Строка         - полное имя файла, содержащего двоичные данные
//                                           электронной подписи.
//                        - Неопределено   - если ИсходныеДанные конверт SOAP.
//
//   ОписаниеОшибки       - Null - вызвать исключение при ошибке проверки.
//                        - Строка - содержит описание ошибки, если произошла ошибка.
// 
//   НаДату               - Дата - проверить сертификат на указанную дату,
//                          если дату не удалось извлечь из подписи или если проверяется КонвертXML.
//                          Если параметр не заполнен, тогда проверять на текущую дату сеанса,
//                          если дату не удалось извлечь из подписи или если проверяется КонвертXML.
//   РезультатСтруктура   - см. ЭлектроннаяПодписьКлиентСервер.РезультатПроверкиПодписи.
//
// Возвращаемое значение:
//  Булево - Истина, если проверка выполнена успешно.
//           Ложь,   если не удалось получить менеджер криптографии (когда не указан),
//                   или произошла ошибка указанная в параметре ОписаниеОшибки.
//
Функция ПроверитьПодпись(МенеджерКриптографии, ИсходныеДанные, Подпись, ОписаниеОшибки = Null, НаДату = Неопределено, РезультатСтруктура = Неопределено) Экспорт
	
	Если РезультатСтруктура <> Неопределено Тогда
		ОжидаемыеЗначения = Новый Массив;
		ОжидаемыеЗначения.Добавить(ЭлектроннаяПодписьСлужебныйКлиентСервер.ПроверятьКвалифицированные());
		ОжидаемыеЗначения.Добавить(ЭлектроннаяПодписьСлужебныйКлиентСервер.ТолькоКвалифицированные());
		ОжидаемыеЗначения.Добавить(ЭлектроннаяПодписьСлужебныйКлиентСервер.НеПроверятьСертификат());
		ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("ЭлектроннаяПодпись.ПроверитьПодпись",
			"РезультатСтруктура.ПараметрыПроверкиСертификата", РезультатСтруктура.ПараметрыПроверкиСертификата, Тип("Строка"),, ОжидаемыеЗначения);
	КонецЕсли;

	РезультатПроверки = Ложь;
	НеверныйХеш = Неопределено;
	ДатаПодписиИзМетки = Неопределено;
	СвойстваПодписи = Неопределено;
	
	ВызыватьИсключение = ОписаниеОшибки = Null;
	
	ИсходныеДанныеДляПроверки = ИсходныеДанные;
	Если ТипЗнч(ИсходныеДанные) = Тип("Строка") И ЭтоАдресВременногоХранилища(ИсходныеДанные) Тогда
		ИсходныеДанныеДляПроверки = ПолучитьИзВременногоХранилища(ИсходныеДанные);
	КонецЕсли;
	
	ЭтоXMLDSig = ТипЗнч(ИсходныеДанныеДляПроверки) = Тип("Структура")
		И ИсходныеДанныеДляПроверки.Свойство("ПараметрыXMLDSig");
	
	Если ЭтоXMLDSig Тогда
		Если Не ИсходныеДанныеДляПроверки.Свойство("КонвертXML") Тогда
			ИсходныеДанныеДляПроверки = Новый Структура(Новый ФиксированнаяСтруктура(ИсходныеДанныеДляПроверки));
			ИсходныеДанныеДляПроверки.Вставить("КонвертXML", ИсходныеДанныеДляПроверки.КонвертSOAP);
		КонецЕсли;
		СвойстваКонвертаXML = ЭлектроннаяПодписьСлужебный.СвойстваКонвертаXML(
			ИсходныеДанныеДляПроверки.КонвертXML, ИсходныеДанныеДляПроверки.ПараметрыXMLDSig, Истина);
		Если СвойстваКонвертаXML <> Неопределено
		   И ЗначениеЗаполнено(СвойстваКонвертаXML.ТекстОшибки) Тогда
			ОписаниеОшибки = СвойстваКонвертаXML.ТекстОшибки;
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура);
			Если ВызыватьИсключение Тогда
				ВызватьИсключение ОписаниеОшибки;
			КонецЕсли;
			Возврат РезультатПроверки;
		КонецЕсли;
	КонецЕсли;
	
	ЭтоCMS = ТипЗнч(ИсходныеДанныеДляПроверки) = Тип("Структура")
		И ИсходныеДанныеДляПроверки.Свойство("ПараметрыCMS");
	
	Если ТипЗнч(Подпись) = Тип("Строка") И ЭтоАдресВременногоХранилища(Подпись) Тогда
		ПодписьДляПроверки = ПолучитьИзВременногоХранилища(Подпись);
	Иначе
		ПодписьДляПроверки = Подпись;
	КонецЕсли;
	
	МенеджерКриптографииДляПроверки = МенеджерКриптографии;
	
	Если МенеджерКриптографииДляПроверки = Неопределено Тогда
		ИспользоватьЭлектроннуюПодписьВМоделиСервиса = Не ЭтоXMLDSig И Не ЭтоCMS
			И ЭлектроннаяПодписьСлужебный.ИспользоватьЭлектроннуюПодписьВМоделиСервиса();
		
		ПараметрыСоздания = ЭлектроннаяПодписьСлужебный.ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ПоказатьОшибку = ВызыватьИсключение И Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса;
		Если ТипЗнч(ПодписьДляПроверки) = Тип("ДвоичныеДанные") Тогда
			ПараметрыСоздания.АлгоритмПодписи =
				ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(ПодписьДляПроверки);
		ИначеЕсли ЭтоXMLDSig Тогда
			Если СвойстваКонвертаXML = Неопределено Тогда
				ДанныеСертификата = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатИзКонвертаSOAP(
					ИсходныеДанныеДляПроверки.КонвертXML, Ложь);
			Иначе
				ДанныеСертификата = Base64Значение(СвойстваКонвертаXML.Сертификат.ЗначениеСертификата);
			КонецЕсли;
			
			ПараметрыСоздания.АлгоритмПодписи =
				ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(ДанныеСертификата);
		КонецЕсли;
		
		МенеджерКриптографииДляПроверки = ЭлектроннаяПодписьСлужебный.МенеджерКриптографии(
			"ПроверкаПодписи", ПараметрыСоздания);
		
		Если МенеджерКриптографииДляПроверки = Неопределено Тогда
			ОписаниеОшибки = ПараметрыСоздания.ОписаниеОшибки;
			Если Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса Тогда
				Если РезультатСтруктура <> Неопределено Тогда
					СвойстваПодписи = ЭлектроннаяПодписьСлужебный.СвойстваПодписиИзДвоичныхДанных(ПодписьДляПроверки, Истина);
					Если ЗначениеЗаполнено(СвойстваПодписи.Сертификат) Тогда
						Сертификат = СвойстваПодписи.Сертификат;
						СвойстваСертификата = СвойстваСертификата(Сертификат);
						СвойстваПодписи.Сертификат = Сертификат;
						СвойстваПодписи.Отпечаток = СвойстваСертификата.Отпечаток;
						СвойстваПодписи.КомуВыданСертификат = СвойстваСертификата.КомуВыдан;
					КонецЕсли;
					ЗаполнитьЗначенияСвойств(РезультатСтруктура, СвойстваПодписи);
					ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура, Истина);
				КонецЕсли;
				Если ВызыватьИсключение Тогда
					ВызватьИсключение ОписаниеОшибки;
				КонецЕсли;
				Возврат РезультатПроверки;
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Если ЭтоXMLDSig Тогда
		Попытка
			Результат = ЭлектроннаяПодписьСлужебный.ПроверитьПодпись(
				ИсходныеДанныеДляПроверки.КонвертXML,
				ИсходныеДанныеДляПроверки.ПараметрыXMLDSig,
				МенеджерКриптографииДляПроверки,
				СвойстваКонвертаXML);
		Исключение
			ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура);
			Если ВызыватьИсключение Тогда
				ВызватьИсключение;
			КонецЕсли;
			Возврат РезультатПроверки;
		КонецПопытки;
		Сертификат     = Результат.Сертификат;
		ДатаДляПроверкиСертификатаПодписи = Результат.ДатаПодписания;
		
		Если РезультатСтруктура <> Неопределено Тогда
			РезультатСтруктура.НеподтвержденнаяДатаПодписи = ДатаДляПроверкиСертификатаПодписи;
			СвойстваСертификата = СвойстваСертификата(Сертификат);
			РезультатСтруктура.Сертификат = Сертификат.Выгрузить();
			РезультатСтруктура.Отпечаток = СвойстваСертификата.Отпечаток;
			РезультатСтруктура.КомуВыданСертификат = СвойстваСертификата.КомуВыдан;
		КонецЕсли;
		
	ИначеЕсли ЭтоCMS Тогда
		Попытка
			Результат = ЭлектроннаяПодписьСлужебный.ПроверитьПодписьCMS(
				ПодписьДляПроверки,
				ИсходныеДанныеДляПроверки.Данные,
				ИсходныеДанныеДляПроверки.ПараметрыCMS,
				МенеджерКриптографииДляПроверки);
		Исключение
			ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура);
			Если ВызыватьИсключение Тогда
				ВызватьИсключение;
			КонецЕсли;
			Возврат РезультатПроверки;
		КонецПопытки;
		
		Сертификат     = Результат.Сертификат;
		ДатаДляПроверкиСертификатаПодписи = Результат.ДатаПодписания;
		
		Если РезультатСтруктура <> Неопределено Тогда
			СвойстваПодписи = ЭлектроннаяПодписьСлужебный.СвойстваПодписиИзДвоичныхДанных(ПодписьДляПроверки, Ложь);
			СвойстваСертификата = СвойстваСертификата(Сертификат);
			СвойстваПодписи.Сертификат = Сертификат.Выгрузить();
			СвойстваПодписи.Отпечаток = СвойстваСертификата.Отпечаток;
			СвойстваПодписи.КомуВыданСертификат = СвойстваСертификата.КомуВыдан;
			ЗаполнитьЗначенияСвойств(РезультатСтруктура, СвойстваПодписи);
		КонецЕсли;
		
	ИначеЕсли МенеджерКриптографииДляПроверки = Неопределено
	      Или МенеджерКриптографииДляПроверки = "СервисКриптографии" Тогда
		
		МодульСервисКриптографии = ОбщегоНазначения.ОбщийМодуль("СервисКриптографии");
		
		Попытка
			Результат = МодульСервисКриптографии.ПроверитьПодпись(ПодписьДляПроверки, ИсходныеДанныеДляПроверки);
		Исключение
			ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура, Истина);
			Если ВызыватьИсключение Тогда
				ВызватьИсключение;
			КонецЕсли;
			Возврат РезультатПроверки;
		КонецПопытки;
		
		СвойстваПодписи = ЭлектроннаяПодписьСлужебный.СвойстваПодписиИзДвоичныхДанных(ПодписьДляПроверки, Истина);
		Если РезультатСтруктура <> Неопределено Тогда
			ЗаполнитьЗначенияСвойств(РезультатСтруктура, СвойстваПодписи);
		КонецЕсли;
		
		Если Не СвойстваПодписи.Успех Тогда
			ОписаниеОшибки = СвойстваПодписи.ТекстОшибки;
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура);
			Если ВызыватьИсключение Тогда
				ВызватьИсключение ОписаниеОшибки;
			КонецЕсли;
			Возврат РезультатПроверки;
		КонецЕсли;
		
		Если СвойстваПодписи.Сертификат = Неопределено Тогда
			ОписаниеОшибки = НСтр("ru = 'Сертификат не существует в данных подписи.'");
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура);
			Если ВызыватьИсключение Тогда
				ВызватьИсключение ОписаниеОшибки;
			КонецЕсли;
			Возврат РезультатПроверки;
		КонецЕсли;
		
		Если Не Результат Тогда
			ОписаниеОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиСервисаПодписьНедействительна();
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура);
			Если ВызыватьИсключение Тогда
				ВызватьИсключение ОписаниеОшибки;
			КонецЕсли;
			Возврат РезультатПроверки;
		КонецЕсли;
		
		Если РезультатСтруктура <> Неопределено Тогда
			ЗаполнитьЗначенияСвойств(РезультатСтруктура, СвойстваПодписи);
		КонецЕсли;
		
		Сертификат = СвойстваПодписи.Сертификат;
		
		ДатаДляПроверкиСертификатаПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДатаДляПроверкиСертификатаПодписи(СвойстваПодписи);
		Если Не ЗначениеЗаполнено(ДатаДляПроверкиСертификатаПодписи) Тогда
			ДатаДляПроверкиСертификатаПодписи = НаДату;
		КонецЕсли;
	Иначе
		Сертификат = Неопределено;
		
		ОшибкаПроверкиПодписи = "";
		Попытка
			МенеджерКриптографииДляПроверки.ПроверитьПодпись(ИсходныеДанныеДляПроверки, ПодписьДляПроверки, Сертификат, Ложь);
			НеверныйХеш = Ложь;
		Исключение
			НеверныйХеш = Истина;
			ОшибкаПроверкиПодписи = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		КонецПопытки;
		
		СвойстваПодписи = ЭлектроннаяПодписьСлужебный.СвойстваПодписиЧтениеМенеджеромКриптографии(
				ПодписьДляПроверки, МенеджерКриптографииДляПроверки, Сертификат = Неопределено);
		Если ПустаяСтрока(ОшибкаПроверкиПодписи) И СвойстваПодписи.ТипПодписи <> Перечисления.ТипыПодписиКриптографии.ОбычнаяCMS
			И СвойстваПодписи.ТипПодписи <> Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES Тогда
			Попытка
				МенеджерКриптографииДляПроверки.ПроверитьПодпись(ИсходныеДанныеДляПроверки, ПодписьДляПроверки,
					Сертификат, Истина);
			Исключение
				ОшибкаПроверкиПодписи = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
			КонецПопытки;
		КонецЕсли;
		
		СвойстваСертификата = Неопределено;
		Если РезультатСтруктура <> Неопределено Тогда
			ЗаполнитьЗначенияСвойств(РезультатСтруктура, СвойстваПодписи);
			Если Не ЗначениеЗаполнено(РезультатСтруктура.Сертификат)
				И ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатСуществует(Сертификат) Тогда
				СвойстваСертификата = СвойстваСертификата(Сертификат);
				РезультатСтруктура.Сертификат = Сертификат.Выгрузить();
				РезультатСтруктура.Отпечаток = СвойстваСертификата.Отпечаток;
				РезультатСтруктура.КомуВыданСертификат = СвойстваСертификата.КомуВыдан;
			КонецЕсли;
		КонецЕсли;
		
		Если Не ПустаяСтрока(ОшибкаПроверкиПодписи) Тогда
			ОписаниеОшибки = ОшибкаПроверкиПодписи;
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура, Неопределено, НеверныйХеш);
			Если ВызыватьИсключение Тогда
				ВызватьИсключение ОписаниеОшибки;
			КонецЕсли;
			Возврат РезультатПроверки;
		КонецЕсли;
		
		ДатаДляПроверкиСертификатаПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДатаДляПроверкиСертификатаПодписи(СвойстваПодписи);
		Если Не ЗначениеЗаполнено(ДатаДляПроверкиСертификатаПодписи) Тогда
			ДатаДляПроверкиСертификатаПодписи = НаДату;
		КонецЕсли;
		
	КонецЕсли;
	
	Если ВызыватьИсключение Тогда
		ОписаниеОшибки = Null;
	КонецЕсли;
	
	Если РезультатСтруктура = Неопределено 
		Или РезультатСтруктура.ПараметрыПроверкиСертификата <> ЭлектроннаяПодписьСлужебныйКлиентСервер.НеПроверятьСертификат() Тогда
			
		ДополнительныеПараметры = ЭлектроннаяПодписьСлужебный.ДополнительныеПараметрыПроверкиСертификата();
		ДополнительныеПараметры.ДляПроверкиПодписи = Истина;
		Если СвойстваПодписи <> Неопределено И ЗначениеЗаполнено(СвойстваПодписи.ДатаПодписиИзМетки) Тогда 
			ДополнительныеПараметры.УказанаДатаМеткиВремени = Истина;
		КонецЕсли;
		Если РезультатСтруктура = Неопределено Тогда
			ДополнительныеПараметры.ВыполнятьПроверкуУдостоверяющегоЦентра = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПроверятьКвалифицированные();
		Иначе
			ДополнительныеПараметры.ВыполнятьПроверкуУдостоверяющегоЦентра = РезультатСтруктура.ПараметрыПроверкиСертификата;
		КонецЕсли;
		
		Если ЗначениеЗаполнено(СвойстваПодписи) И СвойстваПодписи.ТипПодписи = Перечисления.ТипыПодписиКриптографии.АрхивнаяCAdESAv3 Тогда
			ДополнительныеПараметры.ИгнорироватьПроверкуВСпискеОтозванныхСертификатов = Истина;
		КонецЕсли;
		
		РезультатПроверкиСертификата = ЭлектроннаяПодписьСлужебный.ПроверитьСертификат(
			МенеджерКриптографииДляПроверки, Сертификат, ОписаниеОшибки, ДатаДляПроверкиСертификатаПодписи, ДополнительныеПараметры);
		
		Если РезультатПроверкиСертификата = Истина Тогда
			ЗаполнитьРезультатПроверкиПодписи(Истина, РезультатСтруктура);
		Иначе
			ЗаполнитьРезультатПроверкиПодписи(ОписаниеОшибки, РезультатСтруктура, Неопределено, Ложь);
		КонецЕсли;
		
	Иначе
		РезультатПроверкиСертификата = Истина;
		ЗаполнитьРезультатПроверкиПодписи(Истина, РезультатСтруктура);
	КонецЕсли;
		
	Возврат РезультатПроверкиСертификата;
	
КонецФункции

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

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

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

	Возврат Отпечатки;

КонецФункции

// Находит сертификат на компьютере по строке отпечатка.
// Только для работы через средства платформы (МенеджерКриптографии).
//
// Параметры:
//   Отпечаток              - Строка - Base64 кодированный отпечаток сертификата.
//   ТолькоВЛичномХранилище - Булево - если Истина, тогда искать в личном хранилище, иначе везде.
//
// Возвращаемое значение:
//   СертификатКриптографии - сертификат электронной подписи и шифрования.
//   Неопределено - сертификат не существует в хранилище.
//
Функция ПолучитьСертификатПоОтпечатку(Отпечаток, ТолькоВЛичномХранилище) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебный.ПолучитьСертификатПоОтпечатку(Отпечаток, ТолькоВЛичномХранилище);
	
КонецФункции

// Позволяет заполнить справочник ПрограммыЭлектроннойПодписиИШифрования, например, при обновлении ИБ.
// Только для работы через средства платформы (МенеджерКриптографии).
//
// Дополняет стандартный список из двух программ: ViPNet и КриптоПро.
// Если программа с указанными именем и типом уже существует, то ее свойства перезаполняются
// указанными. При заполнении не проверяется корректность указанных свойств.
//
// При заполнении можно использовать поставляемые описания программ,
// список которых находится в процедуре ПоставляемыеНастройкиПрограмм
// модуля менеджера справочника ПрограммыЭлектроннойПодписиИШифрования.
//
// Параметры:
//  ОписаниеПрограмм - Массив - содержит значения типа см. ЭлектроннаяПодпись.НовоеОписаниеПрограммы.
//                              Свойства структуры:
//   * ИмяПрограммы  - Строка - уникальное имя программы, присвоенное ее разработчиком,
//                       например, "Signal-COM CPGOST Cryptographic Provider".
//   * ТипПрограммы  - Число - специальное число, которое описывает тип программы и
//                       дополняет имя программы, например, 75.
//
//   Следующие параметры требуются, если указано Имя и Тип программы,
//   описание которой не поставляется, либо требуется обновить отдельные свойства.
//
//   * Представление       - Строка - наименование программы, которое увидит пользователь,
//                             например, "Сигнал-КОМ CSP (RFC 4357)".
//   * АлгоритмПодписи     - Строка - имя алгоритма подписи, который поддерживает
//                             указанная программа, например, "ECR3410-CP".
//   * АлгоритмХеширования - Строка - имя алгоритма хеширования данных, который поддерживает
//                             указанная программа, например, "RUS-HASH-CP". Используется для подготовки
//                             данных при формировании подписи с помощью алгоритма подписания.
//   * АлгоритмШифрования  - Строка - имя алгоритма шифрования, который поддерживает
//                             указанная программа, например, "GOST28147".
//
// Пример:
//	ОписаниеПрограмм = Новый Массив;
//	
//	// Заполнение дополнительной программы "Сигнал-КОМ CSP (RFC 4357)".
//	ОписаниеПрограммы = ЭлектроннаяПодпись.НовоеОписаниеПрограммы();
//	ОписаниеПрограммы.ИмяПрограммы = "Signal-COM CPGOST Cryptographic Provider";
//	ОписаниеПрограммы.ТипПрограммы = 75;
//	ОписаниеПрограмм.Добавить(ОписаниеПрограммы);
//	
//	// Изменение алгоритма поставляемой программы ViPNet CSP.
//	ОписаниеПрограммы = ЭлектроннаяПодпись.НовоеОписаниеПрограммы();
//	ОписаниеПрограммы.ИмяПрограммы = "Infotecs Cryptographic Service Provider";
//	ОписаниеПрограммы.ТипПрограммы = 2;
//	ОписаниеПрограммы.АлгоритмПодписи = "GOST R 34.10-2001";
//	ОписаниеПрограмм.Добавить(ОписаниеПрограммы);
//	
//	ЭлектроннаяПодпись.ЗаполнитьСписокПрограмм(ОписаниеПрограмм);
//
Процедура ЗаполнитьСписокПрограмм(ОписаниеПрограмм) Экспорт
	
	ПоставляемыеНастройки = Справочники.ПрограммыЭлектроннойПодписиИШифрования.ПоставляемыеНастройкиПрограмм();
	
	ВыполняетсяОбновлениеИнформационнойБазы =
		    ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы()
		Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления();
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Программы.Ссылка КАК Ссылка,
	|	Программы.ИмяПрограммы,
	|	Программы.ТипПрограммы
	|ИЗ
	|	Справочник.ПрограммыЭлектроннойПодписиИШифрования КАК Программы";
	
	Блокировка = Новый БлокировкаДанных;
	Блокировка.Добавить("Справочник.ПрограммыЭлектроннойПодписиИШифрования");
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		Выгрузка = Запрос.Выполнить().Выгрузить();
		
		Для Каждого ОписаниеПрограммы Из ОписаниеПрограмм Цикл
			Отбор = Новый Структура;
			Отбор.Вставить("ИмяПрограммы", ОписаниеПрограммы.ИмяПрограммы);
			Отбор.Вставить("ТипПрограммы", ОписаниеПрограммы.ТипПрограммы);
			
			Строки = Выгрузка.НайтиСтроки(Отбор);
			Если Строки.Количество() > 0 Тогда
				ПрограммаОбъект = Строки[0].Ссылка.ПолучитьОбъект();
			Иначе
				ПрограммаОбъект = Справочники.ПрограммыЭлектроннойПодписиИШифрования.СоздатьЭлемент();
			КонецЕсли;
			
			ОбновитьЗначение(ПрограммаОбъект.ПометкаУдаления, Ложь);
			Если Не ЗначениеЗаполнено(ПрограммаОбъект.РежимИспользования) Тогда
				ОбновитьЗначение(ПрограммаОбъект.РежимИспользования, Перечисления.РежимыИспользованияПрограммыЭлектроннойПодписи.Настроено);
			КонецЕсли;
			
			Строки = ПоставляемыеНастройки.НайтиСтроки(Отбор);
			Для Каждого КлючИЗначение Из ОписаниеПрограммы Цикл
				ИмяПоля = ?(КлючИЗначение.Ключ = "Представление", "Наименование", КлючИЗначение.Ключ);
				Если КлючИЗначение.Значение <> Неопределено Тогда
					ОбновитьЗначение(ПрограммаОбъект[ИмяПоля], КлючИЗначение.Значение, Истина);
				ИначеЕсли Строки.Количество() > 0 Тогда
					ОбновитьЗначение(ПрограммаОбъект[ИмяПоля], Строки[0][КлючИЗначение.Ключ], Истина);
				КонецЕсли;
			КонецЦикла;
			
			Если Не ПрограммаОбъект.Модифицированность() Тогда
				Продолжить;
			КонецЕсли;
			
			Если ВыполняетсяОбновлениеИнформационнойБазы Тогда
				ОбновлениеИнформационнойБазы.ЗаписатьДанные(ПрограммаОбъект);
			Иначе
				ПрограммаОбъект.Записать();
			КонецЕсли;
		КонецЦикла;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

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

// См. ЭлектроннаяПодписьКлиент.КонвертXML.
Функция КонвертXML(Параметры) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.КонвертXML(Параметры);
	
КонецФункции

// См. ЭлектроннаяПодписьКлиент.ПараметрыКонвертаXML.
Функция ПараметрыКонвертаXML() Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыКонвертаXML();
	
КонецФункции

// См. ЭлектроннаяПодписьКлиент.ПараметрыXMLDSig.
Функция ПараметрыXMLDSig() Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыXMLDSig();
	
КонецФункции

// См. ЭлектроннаяПодписьКлиент.ПараметрыCMS.
Функция ПараметрыCMS() Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыCMS();
	
КонецФункции

// Возвращает результат проверки удостоверяющего центра.
// 
// Параметры:
//  Сертификат - СертификатКриптографии
//  НаДату - Неопределено, Дата - если не указана, то проверка выполняется на дату сеанса.
//  ПараметрыПроверки - Структура:
//   * ЭтоПроверкаПодписи - Булево - это проверка подписи, предупреждение (не ошибка) не будет заполнено.
//   * ПроверятьСертификат - Строка - 
//       "ПроверятьКвалифицированные" - (по умолчанию) разрешать подписывать НЭП и проверять КЭП на действительность 
//                                      с учетом списка разрешенных неаккредитованных УЦ.
//       "ТолькоКвалифицированные" - разрешать подписывать только КЭП и не учитывать список разрешенных
//                                   неаккредитованных УЦ.
//
// Возвращаемое значение:
//  Структура - результат проверки удостоверяющего центра по умолчанию:
//   * Действует - Булево - аккредитованный УЦ действует на дату проверки или проверка не выполнялась (сертификат 
//                 неквалифицированный или УЦ не найден в списке аккредитованных)
//   * НайденВСпискеУдостоверяющихЦентров - Булево - сертификат, выданный УЦ является квалифицированным
//   * Государственный - Булево - относится к определенному списку УЦ, выдающих сертификаты, по которым не нужно
//                                выполнять некоторые проверки.
//   например, в России: УЦ ФНС России, Казначейства России, и Банка России.
//   * ЭтоКвалифицированныйСертификат - Булево - сертификат выдан в период аккредитации УЦ.
//   * Предупреждение - Структура - сообщение об ошибке/предупреждение для проверяемого сертификата:
//                       ** ТекстОшибки - Строка
//                       ** ВозможенПеревыпуск - Булево - можно подать заявление на новый сертификат из программы.
//                       ** Причина - Строка - причина ошибки для отображения в расширенной форме ошибки.
//                       ** Решение - Строка - рекомендация для отображения в расширенной форме ошибки.
//
Функция РезультатПроверкиУдостоверяющегоЦентраСертификата(Сертификат, НаДату = Неопределено, ПараметрыПроверки = Неопределено) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебный.РезультатПроверкиУдостоверяющегоЦентраСертификата(Сертификат, НаДату, ПараметрыПроверки);
	
КонецФункции

// Сохраняет настройки текущего пользователя для работы с электронной подписью.
// 
// Параметры:
//  ПерсональныеНастройки - см. ПерсональныеНастройки
//
Процедура СохранитьПерсональныеНастройки(ПерсональныеНастройки) Экспорт
	
	ЭлектроннаяПодписьСлужебный.СохранитьПерсональныеНастройки(ПерсональныеНастройки);
	
КонецПроцедуры

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

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

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

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

// Устарела. Всегда возвращает Истина.
//
// Возвращаемое значение:
//  Булево - если Истина, электронные подписи используются.
//
Функция ДоступнаУсовершенствованнаяПодпись() Экспорт
	
	Возврат Истина;

КонецФункции

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

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

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

#Область СлужебныйПрограммныйИнтерфейс

// Подпись из двоичных данных.
// 
// Параметры:
//  ДанныеПодписи - ДвоичныеДанные
//                - Строка - адрес во временном хранилище
// 
// Возвращаемое значение:
//  ДвоичныеДанные - подпись из двоичных данных в кодировке DER
//
Функция ПодписьВКодировкеDER(ДанныеПодписи) Экспорт
	
	ДвоичныеДанные = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДвоичныеДанныеИзДанных(ДанныеПодписи,
		"ЭлектроннаяПодпись.ПодписьВКодировкеDER");
	
	ПолноеИмяВременногоФайла = ПолучитьИмяВременногоФайла();
	ДвоичныеДанные.Записать(ПолноеИмяВременногоФайла);
	Текст = Новый ТекстовыйДокумент;
	Текст.Прочитать(ПолноеИмяВременногоФайла);
	
	Попытка
		УдалитьФайлы(ПолноеИмяВременногоФайла);
	Исключение
		ЗаписьЖурналаРегистрации(
			НСтр("ru = 'Электронная подпись.Удаление временного файла'",
				ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка, , ,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	
	СтрокаBase64 = Неопределено;
	Если Текст.КоличествоСтрок() > 3 И СтрНачинаетсяС(Текст.ПолучитьСтроку(1), "-----BEGIN")
		И СтрНачинаетсяС(Текст.ПолучитьСтроку(Текст.КоличествоСтрок()), "-----END") Тогда
		Текст.УдалитьСтроку(1);
		Текст.УдалитьСтроку(Текст.КоличествоСтрок());
		СтрокаBase64 = Текст.ПолучитьТекст();
	ИначеЕсли СтрНачинаетсяС(Текст.ПолучитьСтроку(1), "MI") Тогда
		СтрокаBase64 = Текст.ПолучитьТекст();
	КонецЕсли;
	
	Если СтрокаBase64 <> Неопределено Тогда
		Попытка
			ДвоичныеДанные = Base64Значение(СтрокаBase64);
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось получить данные из файла подписи по причине:
						|%1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		КонецПопытки;
	КонецЕсли;
	
	Возврат ДвоичныеДанные;
	
КонецФункции

// Возвращает признак доступности просмотра зашифрованных данных.
//
// Возвращаемое значение:
//  Булево - если Истина, просмотр зашифрованных данных доступен.
//
Функция РасшифровкаДанных() Экспорт
	
	Возврат ШифрованиеИРасшифровкаДанных()
		Или ИспользоватьШифрование() И Пользователи.РолиДоступны("РасшифровкаДанных");
		
КонецФункции

// Возвращает признак доступности шифрования данных.
//
// Возвращаемое значение:
//  Булево - если Истина, шифрование данных доступно.
//
Функция ШифрованиеИРасшифровкаДанных() Экспорт
	
	Возврат ИспользоватьШифрование() И Пользователи.РолиДоступны("ШифрованиеИРасшифровкаДанных");
	
КонецФункции

// Возвращает признак доступности добавления электронных подписей.
//
// Возвращаемое значение:
//  Булево - если Истина, добавление электронных подписей доступно.
//
Функция ДобавлениеИзменениеЭлектронныхПодписей() Экспорт
	
	// АПК:515-выкл
	// Роль не содержит прав на объекты метаданных, кроме общей формы ДобавлениеЭлектроннойПодписиИзФайла.
	Возврат ИспользоватьЭлектронныеПодписи() И Пользователи.РолиДоступны("ДобавлениеИзменениеЭлектронныхПодписей");
	// АПК:515-вкл
	
КонецФункции

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


// Возвращает настройки текущего пользователя для работы с электронной подписью.
//
// Возвращаемое значение:
//   Структура - персональные настройки для работы с электронной подписью:
//       * ДействияПриСохраненииСЭП - Строка - что делать при сохранении файлов с электронной подписью:
//           "Спрашивать" - показывать диалог выбора подписей для сохранения;
//           "СохранятьВсеПодписи" - всегда все подписи.
//       * ПутиКПрограммамЭлектроннойПодписиИШифрования - Соответствие из КлючИЗначение:
//           ** Ключ     - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования - программа.
//           ** Значение - Строка - путь к программе на компьютере пользователя.
//       * РасширениеДляФайловПодписи - Строка - расширение для файлов ЭП.
//       * РасширениеДляЗашифрованныхФайлов - Строка - расширение для зашифрованных файлов.
//       * СохранятьСертификатВместеСПодписью - Булево
//       * ПутьККаталогуДиагностики - Соответствие из КлючИЗначение:
//           ** Ключ - УникальныйИдентификатор - идентификатор клиента.
//           ** Значение - Строка - путь к каталогу.
//
// См. также:
//   ОбщаяФорма.НастройкиЭлектроннойПодписиИШифрования - место определения данных параметров и
//   их текстовые описания.
//
Функция ПерсональныеНастройки() Экспорт
	
	ПерсональныеНастройки = Новый Структура;
	// Начальные значения.
	ПерсональныеНастройки.Вставить("ДействияПриСохраненииСЭП", "Спрашивать");
	ПерсональныеНастройки.Вставить("ПутиКПрограммамЭлектроннойПодписиИШифрования", Новый Соответствие);
	ПерсональныеНастройки.Вставить("РасширениеДляФайловПодписи", "p7s");
	ПерсональныеНастройки.Вставить("РасширениеДляЗашифрованныхФайлов", "p7m");
	ПерсональныеНастройки.Вставить("СохранятьСертификатВместеСПодписью", Ложь);
	ПерсональныеНастройки.Вставить("ПутьККаталогуДиагностики", Новый Соответствие);
	
	КлючПодсистемы = ЭлектроннаяПодписьСлужебный.КлючХраненияНастроек();
	
	Для Каждого КлючИЗначение Из ПерсональныеНастройки Цикл
		СохраненноеЗначение = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(КлючПодсистемы,
			КлючИЗначение.Ключ);
		
		Если ЗначениеЗаполнено(СохраненноеЗначение)
		   И ТипЗнч(КлючИЗначение.Значение) = ТипЗнч(СохраненноеЗначение) Тогда
			
			ПерсональныеНастройки.Вставить(КлючИЗначение.Ключ, СохраненноеЗначение);
		КонецЕсли;
	КонецЦикла;
	
	Возврат ПерсональныеНастройки;
	
КонецФункции

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

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

			ПараметрыСоздания = ЭлектроннаяПодписьСлужебный.ПараметрыСозданияМенеджераКриптографии();
			ПараметрыСоздания.Программа = ЗначенияРеквизитов.Программа;
			ПараметрыСоздания.ОписаниеОшибки = "";
			ПараметрыСоздания.АлгоритмШифрования = АлгоритмШифрования;
			
			МенеджерКриптографии = ЭлектроннаяПодписьСлужебный.МенеджерКриптографии("Шифрование",
				ПараметрыСоздания);

			ОшибкаНаСервере = ПараметрыСоздания.ОписаниеОшибки;
			Если ЗначениеЗаполнено(ОшибкаНаСервере) Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось выполнить шифрование сертификатом ""%1"":
						 |%2'"), Сертификат, ОшибкаНаСервере);
			КонецЕсли;

			Если МенеджерКриптографии = Неопределено Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось выполнить шифрование сертификатом ""%1"":
						|Не удалось создать менеджер криптографии'"), Сертификат);
			КонецЕсли;

			Попытка
				ДвоичныеДанныеРезультата = ЭлектроннаяПодписьСлужебный.Зашифровать(Данные, СертификатКриптографии,
					МенеджерКриптографии);
				Возврат ДвоичныеДанныеРезультата;
			Исключение
				ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось выполнить шифрование сертификатом ""%1"":
						 |%2'"), Сертификат, ОписаниеОшибки);
			КонецПопытки;
			
		КонецЕсли;
		
		СписокОшибок.Добавить(НСтр("ru = 'Недоступно шифрование на сервере.'"));

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

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

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

	ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось выполнить шифрование сертификатом ""%1""'"), Сертификат);
КонецФункции

#Область ОбработчикиРегламентныхЗаданий

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

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

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

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

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

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

// Возвращает общие настройки всех пользователей для работы с электронной подписью.
//
// Возвращаемое значение: 
//   ФиксированнаяСтруктура - общие настройки подсистемы для работы с электронной подписью:
//     * ИспользоватьЭлектронныеПодписи       - Булево - если Истина, то электронный подписи используются.
//     * ИспользоватьШифрование               - Булево - если Истина, то шифрование используются.
//     * ПроверятьЭлектронныеПодписиНаСервере - Булево - если Истина, то электронные подписи и
//                                                       сертификаты проверяются на сервере.
//     * СоздаватьЭлектронныеПодписиНаСервере - Булево - если Истина, то электронные подписи создаются
//                                                       сначала на сервере, а в случае неудачи на клиенте.
//
//     * ОписанияПрограмм - ФиксированныйМассив из см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы -
//                          сведения о поддерживаемых программах криптографии.
//
//     * ОписанияПрограммПоСсылке - ФиксированноеСоответствие из КлючИЗначение:
//         ** Ключ - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//         ** Значение - см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
//
// См. также:
//   ОбщаяФорма.НастройкиЭлектроннойПодписиИШифрования - место определения данных параметров и
//   их текстовые описания.
//
Функция ОбщиеНастройки() Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйПовтИсп.ОбщиеНастройки();
	
КонецФункции

#Область ВспомогательныеПроцедурыИФункции

// Для процедуры ДобавитьПодпись.
Процедура ДобавитьСтрокиПодписи(ОбъектДанных, СвойстваПодписей, СообщениеЖурналаРегистрации)
	
	УстановитьПривилегированныйРежим(Истина);

	ПорядковыйНомер = 1;

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	КОЛИЧЕСТВО(ЭлектронныеПодписи.ПодписанныйОбъект) КАК ПоследнийПорядковыйНомер
	|ИЗ
	|	РегистрСведений.ЭлектронныеПодписи КАК ЭлектронныеПодписи
	|ГДЕ
	|	ЭлектронныеПодписи.ПодписанныйОбъект = &ПодписанныйОбъект";

	Запрос.УстановитьПараметр("ПодписанныйОбъект", ОбъектДанных.Ссылка);

	РезультатЗапроса = Запрос.Выполнить();

	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		ПорядковыйНомер = ВыборкаДетальныеЗаписи.ПоследнийПорядковыйНомер + 1;
	КонецЦикла;

	Если ТипЗнч(СвойстваПодписей) = Тип("Массив") Тогда
		МассивСвойствПодписи = СвойстваПодписей;
	Иначе
		МассивСвойствПодписи = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СвойстваПодписей);
	КонецЕсли;

	Для Каждого СвойстваПодписи Из МассивСвойствПодписи Цикл

		НоваяЗапись = РегистрыСведений.ЭлектронныеПодписи.СоздатьМенеджерЗаписи();
		
		НовыеСвойстваПодписи = ЭлектроннаяПодписьКлиентСервер.НовыеСвойстваПодписи();
		ЗаполнитьЗначенияСвойств(НовыеСвойстваПодписи, СвойстваПодписи);
		ЗаполнитьЗначенияСвойств(НоваяЗапись, СвойстваПодписи, , "Подпись");

		НоваяЗапись.ПодписанныйОбъект = ОбъектДанных.Ссылка;
		НоваяЗапись.Подпись    = Новый ХранилищеЗначения(СвойстваПодписи.Подпись, Новый СжатиеДанных(9));

		НоваяЗапись.ПорядковыйНомер = ПорядковыйНомер;

		Если Не ЗначениеЗаполнено(НоваяЗапись.УстановившийПодпись) Тогда
			НоваяЗапись.УстановившийПодпись = Пользователи.АвторизованныйПользователь();
		КонецЕсли;

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

		Если ДатаПодписи <> Неопределено Тогда
			НоваяЗапись.ДатаПодписи = ДатаПодписи;

		ИначеЕсли Не ЗначениеЗаполнено(НоваяЗапись.ДатаПодписи) Тогда
			НоваяЗапись.ДатаПодписи = ТекущаяДатаСеанса();
		КонецЕсли;
		
		Если Не ЗначениеЗаполнено(НоваяЗапись.ИдентификаторПодписи) Тогда
			НоваяЗапись.ИдентификаторПодписи = Новый УникальныйИдентификатор;
		КонецЕсли;

		СообщениеЖурналаРегистрации = ЭлектроннаяПодписьСлужебный.СведенияОПодписиДляЖурналаРегистрации(
				НоваяЗапись.ДатаПодписи, СвойстваПодписи);

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

// Для процедуры УдалитьПодпись.
Процедура УдалитьСтрокиПодписи(ПодписанныйОбъект, ПорядковыеНомера, СообщениеЖурналаРегистрации)
	
	ЕстьПраваНаУдалениеЧужихПодписей = Пользователи.ЭтоПолноправныйПользователь() 
		Или Пользователи.РолиДоступны("УдалениеЭлектронныхПодписей");

	УстановитьПривилегированныйРежим(Истина);

	Если ТипЗнч(ПорядковыеНомера) = Тип("Массив") Тогда
		МассивПорядковыхНомеров = ПорядковыеНомера;
	Иначе
		МассивПорядковыхНомеров = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПорядковыеНомера);
	КонецЕсли;

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

	Запрос.УстановитьПараметр("МассивПорядковыхНомеров", МассивПорядковыхНомеров);
	Запрос.УстановитьПараметр("ПодписанныйОбъект", ПодписанныйОбъект.Ссылка);

	НачатьТранзакцию();
	Попытка

		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить(Метаданные.РегистрыСведений.ЭлектронныеПодписи.ПолноеИмя());
		ЭлементБлокировки.УстановитьЗначение("ПодписанныйОбъект", ПодписанныйОбъект.Ссылка);
		Блокировка.Заблокировать();

		ВыборкаДетальныеЗаписи = Запрос.Выполнить().Выбрать();
		Если ВыборкаДетальныеЗаписи.Количество() <> МассивПорядковыхНомеров.Количество() Тогда
			ВызватьИсключение НСтр("ru = 'Строка с подписью не существует.'");
		КонецЕсли;

		Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
			МенеджерЗаписи = РегистрыСведений.ЭлектронныеПодписи.СоздатьМенеджерЗаписи();
			ЗаполнитьЗначенияСвойств(МенеджерЗаписи, ВыборкаДетальныеЗаписи);

			МенеджерЗаписи.Прочитать();

			ЕстьПрава = ЕстьПраваНаУдалениеЧужихПодписей 
				Или МенеджерЗаписи.УстановившийПодпись = Пользователи.АвторизованныйПользователь();

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

			СообщениеЖурналаРегистрации = ЭлектроннаяПодписьСлужебный.СведенияОПодписиДляЖурналаРегистрации(
				МенеджерЗаписи.ДатаПодписи, СвойстваПодписи);

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

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

		КонецЦикла;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

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

// Для процедуры ЗаписатьСертификатВСправочник.
Процедура ОбновитьЗначение(СтароеЗначение, НовоеЗначение, ПропускатьНеопределенныеЗначения = Ложь)
	
	Если НовоеЗначение = Неопределено И ПропускатьНеопределенныеЗначения Тогда
		Возврат;
	КонецЕсли;
	
	Если СтароеЗначение <> НовоеЗначение Тогда
		СтароеЗначение = НовоеЗначение;
	КонецЕсли;
	
КонецПроцедуры

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

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

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

Функция ОтпечатокСертификата(Знач Сертификат)
	
	Если ТипЗнч(Сертификат) = Тип("Строка") И ЭтоАдресВременногоХранилища(Сертификат) Тогда
		Сертификат = ПолучитьИзВременногоХранилища(Сертификат);
	КонецЕсли;
	
	Если ТипЗнч(Сертификат) = Тип("ДвоичныеДанные") Тогда
		Сертификат = Новый СертификатКриптографии(Сертификат);
	КонецЕсли;
	
	Возврат ?(ТипЗнч(Сертификат) = Тип("СертификатКриптографии"), Base64Строка(Сертификат.Отпечаток), 
		Строка(Сертификат));
	
КонецФункции 

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

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