Электронная цифровая подпись на сайте при помощи КриптоПро ЭЦП Browser plug-in / Хабр

Электронная цифровая подпись на сайте при помощи КриптоПро ЭЦП Browser plug-in / Хабр Электронная цифровая подпись
Содержание
  1. Почему не работает крипто про эцп браузер плагин
  2. Coogle chrome
  3. Mozilla firefox
  4. Opera
  5. Где и как приобрести электронную подпись
  6. Если вместо параметра метод
  7. Зависимости
  8. Загрузить скрипт можно напрямую из репозитория или с помощью bower
  9. Запись данных (метод set)
  10. Инструкция по настройке окружения для использования криптопро эцп browser plug-in
  11. Использование
  12. Как проверить браузер
  13. Как удалить плагин
  14. Как установить и настроить криптопро эцп browser plug-in в разных браузерах
  15. Настройка криптопро эцп browser plug-in
  16. Особенности некоторых браузеров по настройке работы плагина
  17. Отличия от родной библиотеки
  18. Подписание pdf на js и вставка подписи на c#, используя крипто про
  19. Подписывание данных (метод signdata)
  20. Подпись файла с использованием fileapi и чтением файла по частям
  21. Получение версии криптопро csp (метод getcspversion)
  22. Получение версии плагина (метод getversion)
  23. Получение данных (метод get)
  24. Получение списка сертификатов (метод getcertificates)
  25. Получение цепочки данных (метод get)
  26. Пример проверяющего наличие расширения кода
  27. Проверка криптопро эцп browser plug-in
  28. Проверка подписи криптопро
  29. Процесс настройки
  30. Системные требования
  31. Следующим шагом инициализировать
  32. Установка и настройка крипто про эцп браузер плагин
  33. Установка плагина на unix
  34. Электронная цифровая подпись на сайте при помощи криптопро эцп browser plug-in
  35. Яндекс.браузер

Почему не работает крипто про эцп браузер плагин

Если после перехода на портал разработчика при проверке расширения появляется статус «Недоступен», значит настройки в веб-обозревателе сделаны неправильно. Установите их вновь. Если опять отобразится аналогичное уведомление, то почистите кэш обозревателя и переустановите приложение.

Если при проверке расширения отображается статус «Плагин загружен», но информации о криптопровайдере нет, то не установлен КриптоПро CSP. Загрузите ПО с ресурса разработчика и установите его на ПК. Если после этого не удастся начать работу с плагином, значит, адрес портала не включен в число разрешенных. Перейдите в настройки ПО и в графе «Список доверенных узлов» укажите адреса веб-сайта.

Если при подписании документа появляется ошибка с выводом уведомления «Цепочка сертификатов не создана», воспользуйтесь следующей инструкцией:

  1. Откройте «Пуск», выберите сначала «Все программы», далее «КриптоПро» и «Сертификаты».
  2. В открывшемся списке сначала выберите «Текущий Пользователь», «Личное» и затем «Сертификаты».
  3. В появившемся окне зайдите во вкладку «Путь сертификации». Если отображаются красные метки, то нужно загрузить и инсталлировать промежуточные и корневые сертификаты. Их скачивание происходит с ресурса удостоверяющего центра, где ранее получили документы. После установки перечисленных сертификатов будет создана цепочка доверия, и удастся завершить операцию.

Если при заверке документа система выдает ошибку x8007064A, значит, просрочен ключ у одного из продуктов КриптоПро — CSP, TSP Client 2.0 или OCSP Client 2.0. Для просмотра статуса лицензии перейдите в «Пуск», выберите «КриптоПро» и далее «Управление лицензиями». Найдите ПО с истекшим ключом. Приобретите лицензию повторно.

Подберем электронную подпись для вашего бизнеса за 5 минут!

Оставьте заявку и получите консультацию.

Оцените, насколько полезна была информация в статье?

Coogle chrome

Алгоритм действия для Chrome одинаков независимо от используемой версии ОС:

  1. Запустите интернет-обозреватель.
  2. Откроется окно с уведомлением об установке нового ПО. Нажмите на кнопку «Включить».
  3. Проверьте активацию  приложения. Для этого выберите в меню интернет-обозревателя сначала «Дополнительные инструменты», далее «Расширения».
  4. В перечне должно отобразиться название ранее установленного ПО.
  5. Если программного модуля нет, перейдите в интернет-магазин Chrome. Задайте в поисковой строке название плагина и нажмите «Найти». Откроется веб-страница с описанием ПО и опцией «Установить», активируйте ее. Дождитесь завершения процесса инсталляции и перезапустите интернет-обозреватель.

Вновь откройте браузер. Перейдите в раздел «Расширения» и найдите в перечне название приложения. Активируйте нажатием кнопки «Включить».

Mozilla firefox

Работа программного модуля в Mozilla Firefox поддерживается в версии обозревателя ниже 52. В более свежих версиях браузера использовать ЭЦП не получится. Для проведения настроек в Mozilla Firefox выполните следующие шаги:

  1. Запустите обозреватель. В открывшемся окне вверху справа кликните на иконку с тремя черточками для вызова главного меню. В списке выберите «Дополнения».
  2. Если в открывшемся перечне присутствует установленное ПО, то поставьте галочку напротив пункта «Всегда включать».
  3. Если в перечне отсутствует ранее установленное приложение, откройте в веб-обозревателе новую вкладку и укажите в поисковой строке запрос «config».
  4. На открывшейся странице выберите любой элемент и кликните правой кнопкой мыши. Откроется меню, где активируйте сначала «Создать», затем «Логическое».
  5. Откроется форма, где укажите следующий запрос: «plugin.load_flash_only».
  6. В списке «Значение» активируйте пункт «false».

Перезапустите интернет-обозреватель. Вновь перейдите в «Дополнения» и отметьте «Всегда включать» напротив названия программного модуля.

Opera

Для Opera алгоритм действий выглядит следующим образом:

  1. Откройте интернет-обозреватель.
  2. Выберите «Меню», где в выпадающем списке найдите «Расширения» и кликните двойным щелчком мыши.
  3. На открывшейся странице отобразятся все установленные плагины. Найдите в перечне нужное ПО и щелкните «Включить».
  4. Если в списке не окажется требуемого плагина, в разделе слева активируйте пункт «Добавить расширение». В поисковую строку введите название ПО и щелкните по найденному ярлыку.

На открывшейся странице активируйте опцию «Добавить в Опера».

Где и как приобрести электронную подпись

Квалифицированную электронную подпись могут выдавать только удостоверяющие центры, аккредитованные Минкомсвязи. УЦ «Астрал-М» предлагает электронные подписи с большим выбором тарифных планов и дополнительных услуг.

Для получения квалифицированной электронной подписи нужно проделать четыре простых шага:

  1. Оставьте заявку, заполнив форму обратной связи на странице «Астрал-ЭТ».
  2. Подготовьте необходимый пакет документов и отправьте на проверку специалистам УЦ «Астрал-М».
  3. Оплатите выставленный счёт.
  4. Получите готовую электронную подпись.

Специалисты УЦ «Астрал-М» помогут вам выбрать подходящий тариф и расскажут, какие документы вам понадобятся для выпуска электронной подписи.

Если вместо параметра метод

Иногда чтобы получить очередной параметр надо вызвать метод, например (родной код):

var signingTimeAttr = yield cadesplugin.CreateObjectAsync('CADESCOM.CPAttribute');
yield signingTimeAttr.propset_Name(0);
yield signingTimeAttr.propset_Value(timeNow);

С этой библиотекой будет выглядеть так

var attribute;
altCadesPlugin.get('CADESCOM.CPAttribute').then(function(attribute_){
    attribute = attribute_;
    altCadesPlugin.get(attribute, {method: 'propset_Name', args: [0]});
}).then(function(){
    altCadesPlugin.get(attribute, {method: 'propset_Value', args: [timeNow]});
});

Зависимости

Для корректной работы скрипта необходимы следующие библиотеки

  1. jquery
  2. es6-promise

Загрузить скрипт можно напрямую из репозитория или с помощью bower

В репозитории библитека находится в папке src

src/alt_cadesplugin_api.js

src/alt_cadesplugin_api.min.js

bower install cadesplugin

Запись данных (метод set)

Запишет значение 0 в параметр Name объекта CAdESCOM.CPAttribute

Если плагин работает без NPAPI то не надо заботиться о подставлении префикса propset_, это делается автоматически

altCadesPlugin.get('CAdESCOM.CPAttribute')
.then(function(attribute){
    altCadesPlugin.set(attribute, 'Name', 0);
});

Инструкция по настройке окружения для использования криптопро эцп browser plug-in

КриптоПро ЭЦП Browser plug-in предназначен для создания и проверки электронной подписи (ЭП) на веб-страницах с использованием СКЗИ “КриптоПро CSP”.

КриптоПро ЭЦП Browser plug-in применим в любом из современных браузеров с поддержкой сценариев JavaScript:

  • Google Chrome;
  • Opera;
  • Яндекс.Браузер;
  • Mozilla Firefox;
  • Apple Safari.

Поддерживаемые операционные системы:

  • Microsoft Windows;
  • Linux;
  • Apple iOS;
  • Apple MacOS.

Порядок установки и настройки:

Пройти проверку корректности настройки рабочего окружения

Использование

Для начала создаем экземпляр класса AltCadesPlugin

var altCadesPlugin;
altCadesPlugin = new AltCadesPlugin()

Как проверить браузер

Проверка «КриптоПро ЭЦП Browser plug-in» осуществляется на специальном сервисе разработчика «Cryptopro». Если расширение cadesplugin.exe установлено правильно, оно запросит доступ к сертификатам и ключам при переходе на сайт для проверки. Пользователю необходимо нажать «ОК». Далее появляется уведомление об успешном слиянии модуля, где указаны версия и криптопровайдер.

Читайте также:  Электронная подпись заканчивается — что делать?

Чтобы добавить корневые сертификаты в перечень доверенных, требуется настройка. Для этого необходимо:

Как удалить плагин

Чтобы удалить «КриптоПро ЭЦП Browser plug-in» необходимо выполнить следующие действия:

  1. зайти в панель управления нажав кнопку меню «Пуск», далее «Параметры»;
  2. перейти в раздел управления программами в соответствии с версией Windows — «Установка и удаление программ» для Windows XP, «Программы и компоненты» для Windows Vista, Windows 7, Windows 8 или «Приложения» для Windows 10;
  3. в открывшемся окне выбрать программу «КриптоПро ЭЦП Browser Plug-in»;
  4. нажать «Удалить»;
  5. перезагрузить ПК.

Как установить и настроить криптопро эцп browser plug-in в разных браузерах

Установка «КриптоПро ЭЦП Browser plug-in» имеет различия в зависимости от браузера. На любой из браузеров нужно установить соответствующее расширение (дополнение).

Настройка криптопро эцп browser plug-in

  1. В браузереGoogle Chrome
    • Запустите Google Chrome. Ожидайте скрытой установки плагина.
    • По завершении установки плагина появится уведомление о том, что в браузер добавлено расширение или приложение: CryptoPro Extension for CAdES Browser Plug-in.
    • Нажмите кнопку “Включить расширение”.
    • Если расширение браузера не установилось, можете установить его вручную.
  1. В браузерах Яндекс.Браузер и браузер Opera
    • Перейдите по ссылке и установите расширение.
  2. В браузереFireFox
    • Перейдите по ссылке и установите расширение.
    • Нажмите кнопку “Добавить”.

Особенности некоторых браузеров по настройке работы плагина

  • в Mozilla Firefox 29 и выше: необходимо включить работу плагина (браузер может не запросить разрешения на включение плагина). Для этого пройти диагностику и выполнить фикс «Включение плагинов в Mozilla Firefox», после чего обязательно перезапустить Firefox. Также это можно сделать вручную: нажать Ctrl Shift A, перейти в раздел «Плагины», выбрать CryptoPro CAdES NPAPI Browser Plug-in и перевести его в состояние «Всегда включать» (Always active), после чего обязательно перезапустить Firefox.
  • в Google Chrome необходимо зайти по ссылке и установить расширение.
  • В Yandex Browser и Opera нужно установить расширение, доступное по этой ссылке
  • В Internet Explorer необходимо сделать следующие настройки:

Отличия от родной библиотеки

  1. Не запускает проверку плагина сразу при загрузке файла
  2. Использует jQuery.Deferred вместо нативных промисов
  3. Может подключаться к проекту как обычная библиотека, а также как amd/commonjs/node модуль

Подписание pdf на js и вставка подписи на c#, используя крипто про

Итак. Пришла задача. Используя браузер предложить пользователю подписать PDF электронной подписью (далее ЭП). У пользователя должен быть токен, содержащий сертификат, открытый и закрытый ключ. Далее на сервере надо вставить подпись в PDF документ. После этого надо проверить подпись на валидность. В качестве back-end используем ASP.NET и соответственно C#.

Вся соль в том, что надо использовать подпись в формате CAdES-X Long Type 1, и российские ГОСТ Р 34.10-2001, ГОСТ Р 34.10-2021 и т.п. Кроме того подписей может быть более одной, то есть пользователи могут по очереди подписывать файл. При этом предыдущие подписи должны оставаться валидными.

В процессе решения задачу решили усложнить для нас, и уменьшить объем передаваемых данных на клиент. Передавать только hash документа, но не сам документ.

В исходниках буду опускать малозначимые для темы моменты, оставлю только то что касается криптографии. Код на JS приведу только для нормальных браузеров, JS-движки которых поддерживают Promise и function generator. Думаю кому нужно для IE напишут сами (мне пришлось «через не хочу»).

Что нужно:

  1. Пользователь должен получить пару ключей и сертификат.
  2. Пользователь должен установить plug-in от Крипто ПРО. Без этого средствами JS мы не сможем работать с криптопровайдером.

Замечания:

  1. Для тестов у меня был сертификат выданный тестовым ЦС Крипто ПРО и нормальный токен, полученный одним из наших сотрудников (на момент написания статьи ~1500р с годовой лицензией на Крипто ПРО и двумя сертификатами: но «новому» и «старому» ГОСТ)
  2. Говорят, plug-in умеет работать и с ViPNet, но я не проверял.

Теперь будем считать что у нас на сервере есть готовый для подписывания PDF.

Добавляем на страницу скрипт от Крипто ПРО:

<script src="/Scripts/cadesplugin_api.js" type="text/javascript"></script>

Дальше нам надо дождаться пока будет сформирован объект cadesplugin

window.cadespluginLoaded = false;
cadesplugin.then(function () {
    window.cadespluginLoaded = true;
});

Запрашиваем у сервера hash. Предварительно для этого нам ещё надо знать каким сертификатом, а значит и алгоритмом пользователь будет подписывать. Маленькая ремарка: все функции и «переменные» для работы с криптографией на стороне клиента я объединил в объект CryptographyObject.

Метод заполнения поля certificates объекта CryptographyObject:

    fillCertificates: function (failCallback) {

            cadesplugin.async_spawn(function*() {
                try {
                    let oStore = yield cadesplugin.CreateObjectAsync("CAPICOM.Store");

                    oStore.Open(cadesplugin.CAPICOM_CURRENT_USER_STORE,
                        cadesplugin.CAPICOM_MY_STORE,
                        cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED);

                    let certs = yield oStore.Certificates;
                    certs = yield certs.Find(cadesplugin.CAPICOM_CERTIFICATE_FIND_TIME_VALID);
                    let certsCount = yield certs.Count;
                    for (let i = 1; i <= certsCount; i  ) {
                        let cert = yield certs.Item(i);
                        CryptographyObject.certificates.push(cert);
                    }
                    oStore.Close();
                } catch (exc) {
                     failCallback(exc);
                }
            });
    }

Комментарий: пробуем открыть хранилище сертификатов. В этот момент система пользователя выдаст предупреждение, что сайт пытается что-то сделать с сертификатами, криптографией и прочей магической непонятной ерундой. Пользователю тут надо будет нажать кнопку «Да»

Далее получаем сертификаты, валидные по времени (не просроченные) и складываем их в массив certificates. Это надо сделать из-за асинхронной природы cadesplugin (для IE всё иначе 😉 ).

Метод получения hash:

getHash: function (certIndex, successCallback, failCallback, какие-то ещё параметры) {
        try {
            cadesplugin.async_spawn(function*() {
                let cert = CryptographyObject.certificates[certIndex];
                let certPublicKey = yield cert.PublicKey();
                let certAlgorithm = yield certPublicKey.Algorithm;
                let algorithmValue = yield certAlgorithm.Value;
                let hashAlgorithm;
                //определяем алгоритм подписания по данным из сертификата и получаем алгоритм хеширования
                    if (algorithmValue === "1.2.643.7.1.1.1.1") {
                        hashAlgorithm = "2021256";
                    } else if (algorithmValue === "1.2.643.7.1.1.1.2") {
                        hashAlgorithm = "2021512";
                    } else if (algorithmValue === "1.2.643.2.2.19") {
                        hashAlgorithm = "3411";
                    } else {
                        failCallback("Реализуемый алгоритм не подходит для подписания документа.");
                        return;
                    }

                $.ajax({
                    url: "/Services/SignService.asmx/GetHash",
                    method: "POST",
                    contentType: "application/json; charset=utf-8 ",
                    dataType: "json",
                    data: JSON.stringify({
                        //какие-то данные для определения документа
                        //не забудем проверить на сервере имеет ли пользователь нужные права
                        hashAlgorithm: hashAlgorithm,
                    }),
                    complete: function (response) {
                        //получаем ответ от сервера, подписываем и отправляем подпись на сервер
                        if (response.status === 200) {
                            CryptographyObject.signHash(response.responseJSON,
                                function(data) {
                                    $.ajax({
                                        url: CryptographyObject.signServiceUrl,
                                        method: "POST",
                                        contentType: "application/json; charset=utf-8",
                                        dataType: "json",
                                        data: JSON.stringify({
                                            Signature: data.Signature,
                                            //какие-то данные для определения файла
                                            //не забудем про серверную валидацию и авторизацию
                                        }),
                                        complete: function(response) {
                                            if (response.status === 200)
                                                successCallback();
                                            else
                                                failCallback();
                                        }
                                    });
                                },
                                certIndex);
                        } else {
                            failCallback();
                        }
                    }
                });
            });
        } catch (exc) {
            failCallback(exc);
        }
    }

Комментарий: обратите внимание на cadesplugin.async_spawn, в нее передаётся функция-генератор, на которой последовательно вызывается next(), что приводит к переходу к yield.

Таким образом получается некий аналог async-await из C#. Всё выглядит синхронно, но работает асинхронно.

Теперь что происходит на сервере, когда у него запросили hash.

Во-первых необходимо установить nuget-пакет iTextSharp (на момент написания стать актуальная версия 5.5.13)

Во-вторых нужен CryptoPro.Sharpei, он идёт в нагрузку к Крипто ПРО .NET SDK

Теперь можно получать hash

                //определим hash-алгоритм
                HashAlgorithm hashAlgorithm;

                switch (hashAlgorithmName)
                {
                    case "3411":
                        hashAlgorithm = new Gost3411CryptoServiceProvider();
                        break;
                    case "2021256":
                        hashAlgorithm = new Gost3411_2021_256CryptoServiceProvider();
                        break;
                    case "2021512":
                        hashAlgorithm = new Gost3411_2021_512CryptoServiceProvider();
                        break;
                    default:
                        GetLogger().AddError("Неизвестный алгоритм хеширования", $"hashAlgorithmName: {hashAlgorithmName}");
                        return HttpStatusCode.BadRequest;
                }
                //получим hash в строковом представлении, понятном cadesplugin
                string hash;
                using (hashAlgorithm)
                //downloadResponse.RawBytes - просто массив байт исходного PDF файла
                using (PdfReader reader = new PdfReader(downloadResponse.RawBytes))
                {
                    //ищем уже существующие подписи
                    int existingSignaturesNumber = reader.AcroFields.GetSignatureNames().Count;
                    using (MemoryStream stream = new MemoryStream())
                    {
                        //добавляем пустой контейнер для новой подписи
                        using (PdfStamper st = PdfStamper.CreateSignature(reader, stream, '', null, true))
                        {
                            PdfSignatureAppearance appearance = st.SignatureAppearance;
                            //координаты надо менять в зависимости от существующего количества подписей, чтоб они не наложились друг на друга
                            appearance.SetVisibleSignature(new Rectangle(36, 100, 164, 150), reader.NumberOfPages,
                                //задаём имя поля, оно потом понадобиться для вставки подписи
                                $"{SignatureFieldNamePrefix}{existingSignaturesNumber   1}");
                            //сообщаем, что подпись придёт извне
                            ExternalBlankSignatureContainer external =
                                new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
                            //третий параметр - сколько места в байтах мы выделяем под подпись
                            //я выделяю много, т.к. CAdES-X Long Type 1 содержит все сертификаты по цепочке до самого корневого центра
                            MakeSignature.SignExternalContainer(appearance, external, 65536);
                            //получаем поток, который содержит последовательность, которую мы хотим подписывать
                            using (Stream contentStream = appearance.GetRangeStream())
                            {
                                //вычисляем hash и переводим его в строку, понятную cadesplugin
                                hash = string.Join(string.Empty,
                                    hashAlgorithm.ComputeHash(contentStream).Select(x => x.ToString("X2")));
                            }
                        }
                        //сохраняем stream куда хотим, он нам пригодиться, что бы вставить туда подпись
                    }
                }

На клиенте, получив hash от сервера подписываем его

    //certIndex - индекс в массиве сертификатов. На основании именно этого сертификата мы получали алгоритм и формировали hash на сервере
    signHash: function (data, callback, certIndex, failCallback) {
        try {
            cadesplugin.async_spawn(function*() {
                certIndex = certIndex | 0;

                let oSigner = yield cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");

                let cert = CryptographyObject.certificates[certIndex];

                oSigner.propset_Certificate(cert);
                oSigner.propset_Options(cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN);
                //тут надо указать нормальный адрес TSP сервера. Это тестовый от Крипто ПРО
                oSigner.propset_TSAAddress("https://www.cryptopro.ru/tsp/");

                let hashObject = yield cadesplugin.CreateObjectAsync("CAdESCOM.HashedData");

                let certPublicKey = yield cert.PublicKey();
                let certAlgorithm = yield certPublicKey.Algorithm;
                let algorithmValue = yield certAlgorithm.Value;

                if (algorithmValue === "1.2.643.7.1.1.1.1")  {
                    yield hashObject.propset_Algorithm(cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2021_256);
                    oSigner.propset_TSAAddress(CryptographyObject.tsaAddress2021);
                } else if (algorithmValue === "1.2.643.7.1.1.1.2") {
                    yield hashObject.propset_Algorithm(cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2021_512);
                    oSigner.propset_TSAAddress(CryptographyObject.tsaAddress2021);
                } else if (algorithmValue === "1.2.643.2.2.19") {
                    yield hashObject.propset_Algorithm(cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411);
                    oSigner.propset_TSAAddress(CryptographyObject.tsaAddress2001);
                } else {
                    alert("Невозможно подписать документ этим сертификатом");
                    return;
                }
                //в объект описания hash вставляем уже готовый hash с сервера
                yield hashObject.SetHashValue(data.Hash);

                let oSignedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
                oSignedData.propset_ContentEncoding(cadesplugin.CADESCOM_BASE64_TO_BINARY);
                //результат подписания в base64
                let signatureHex =
                    yield oSignedData.SignHash(hashObject, oSigner, cadesplugin.CADESCOM_CADES_X_LONG_TYPE_1);

                data.Signature = signatureHex;
                callback(data);
            });
        } catch (exc) {
            failCallback(exc);
        }
    }

Комментарий: полученную подпись отправляем на сервер (см. выше)

Читайте также:  Сертификат электронной подписи: общее понятие и содержание, правила действия

Ну и наконец вставляем подпись в документ на стороне сервера


//всякие нужные проверки
                //downloadResponse.RawBytes - ранее созданный PDF с пустым контейнером для подписи
                using (PdfReader reader = new PdfReader(downloadResponse.RawBytes))
                {
                    using (MemoryStream stream = new MemoryStream())
                    {
                        //requestData.Signature - собственно подпись от клиента
                        IExternalSignatureContainer external = new SimpleExternalSignatureContainer(Convert.FromBase64String(requestData.Signature));
                    //lastSignatureName - имя контейнера, которое мы определили при формировании hash
                        MakeSignature.SignDeferred(reader, lastSignatureName, stream, external);
                        
                    //сохраняем подписанный файл
                    }
                }

Комментарий: SimpleExternalSignatureContainer — это простейший класс, реализующий интерфейс IExternalSignatureContainer

        /// <summary>
        /// Простая реализация контейнера внешней подписи
        /// </summary>
        private class SimpleExternalSignatureContainer : IExternalSignatureContainer
        {
            private readonly byte[] _signedBytes;

            public SimpleExternalSignatureContainer(byte[] signedBytes)
            {
                _signedBytes = signedBytes;
            }

            public byte[] Sign(Stream data)
            {
                return _signedBytes;
            }

            public void ModifySigningDictionary(PdfDictionary signDic)
            {

            }
        }

Собственно с подписанием PDF на этом всё. Проверка будет описана в продолжении статьи. Надеюсь, она будет…

Внёс исправления из комментария о получении Oid алгоритма подписи. Спасибо

Подписывание данных (метод signdata)

altCadesPlugin.getCertificates()
.then(function(certificates){
    certificate = certificates[0].certificate;
    altCadesPlugin.signData('Hello World!', certificate);
}).then(function(signature){
    alert(signature);
});

Подпись файла с использованием fileapi и чтением файла по частям

Пример создания и проверки подписи файла с использованием FileAPI и чтением файла по частям

Приведенный пример использует синхронную версию плагина. Также см. пример работы с асинхронными обьектами.

JavaScript

        var CADESCOM_CADES_BES = 1;
        var CAPICOM_CURRENT_USER_STORE = 2;
        var CAPICOM_MY_STORE = "My";
        var CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED = 2;
        var CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1;
        var CADESCOM_BASE64_TO_BINARY = 1;

        function signCreate(certSubjectName, oHashedData) {
            var oStore = cadesplugin.CreateObject("CAdESCOM.Store");
            oStore.Open(CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE,
                CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED);

            var oCertificates = oStore.Certificates.Find(
                CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, certSubjectName);
            if (oCertificates.Count == 0) {
                alert("Certificate not found: "   certSubjectName);
                return;
            }
            var oCertificate = oCertificates.Item(1);
            var oSigner = cadesplugin.CreateObject("CAdESCOM.CPSigner");
            oSigner.Certificate = oCertificate;

            var oSignedData = cadesplugin.CreateObject("CAdESCOM.CadesSignedData");
            oSignedData.ContentEncoding = CADESCOM_BASE64_TO_BINARY;

            try {
                var sSignedMessage = oSignedData.SignHash(oHashedData, oSigner, CADESCOM_CADES_BES);
            } catch (err) {
                alert("Failed to create signature. Error: "   cadesplugin.getLastError(err));
                return;
            }

            oStore.Close();

            return sSignedMessage;
        }

        function Verify(sSignedMessage, oHashedData) {
            var oSignedData = cadesplugin.CreateObject("CAdESCOM.CadesSignedData");
            try {
                oSignedData.VerifyHash(oHashedData, sSignedMessage, CADESCOM_CADES_BES);
            } catch (err) {
                alert("Failed to verify signature. Error: "   cadesplugin.getLastError(err));
                return false;
            }

            return true;
        }

        function signFile(file, certSubjectName) {
            var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
            var chunkSize = 3 * 1024 * 1024; // 3MB
            var chunks = Math.ceil(file.size / chunkSize);
            var currentChunk = 0;

            var oHashedData = cadesplugin.CreateObject("CAdESCOM.HashedData");
            oHashedData.DataEncoding = CADESCOM_BASE64_TO_BINARY;

            var progress = document.getElementById("progressbar").childNodes.item(1);

            var frOnload = function(e) {
                var header = ";base64,";
                var sFileData = e.target.result;
                var sBase64Data = sFileData.substr(sFileData.indexOf(header)   header.length);

                oHashedData.Hash(sBase64Data);

                var percentLoaded = Math.round((currentChunk / chunks) * 100);
                // Increase the progress bar length.
                if (percentLoaded <= 100) {
                    progress.style.width = percentLoaded   '%';
                    progress.textContent = percentLoaded   '%';
                }

                currentChunk  ;

                if (currentChunk < chunks) {
                    loadNext();
                }
                else {
                    document.getElementById("progressbar").style.visibility = "hidden";
                    var signedMessage = signCreate(certSubjectName, oHashedData);
                    // Выводим отделенную подпись в BASE64 на страницу
                    // Такая подпись должна проверяться в КриптоАРМ и cryptcp.exe
                    document.getElementById("signature").innerHTML = signedMessage;

                    // Проверим подпись
                    var verifyResult = Verify(signedMessage, oHashedData);
                    if (verifyResult) {
                        alert("Signature verified");
                    }
                }
            };

            var frOnerror = function() {
                alert("File load error.");
            };

            function loadNext() {
                var fileReader = new FileReader();
                fileReader.onload = frOnload;
                fileReader.onerror = frOnerror;

                var start = currentChunk * chunkSize,
                end = ((start   chunkSize) >= file.size) ? file.size : start   chunkSize;

                fileReader.readAsDataURL(blobSlice.call(file, start, end));
            };

            loadNext();
        }

        function doCheck() {
            // Проверяем, работает ли File API
            if (window.FileReader) {
                // Браузер поддерживает File API.
            } else {
                alert("The File APIs are not fully supported in this browser.");
            }
            var fileReader = new FileReader();
            if (typeof(fileReader.readAsDataURL)!="function") {
                alert("Method readAsDataURL() is not supported in FileReader.");
                return;
            }
        }

        function doSign() {
            // Проверяем, работает ли File API
            doCheck();
            if (1 != document.getElementById("uploadFile").files.length) {
                alert("Select the file.");
                return;
            }

            var oFile = document.getElementById("uploadFile").files[0];

            var oCertName = document.getElementById("CertName");
            var sCertName = oCertName.value; // Здесь следует заполнить SubjectName сертификата
            if ("" == sCertName) {
                alert("Введите имя сертификата (CN).");
                return;
            }
            signFile(oFile, sCertName);
        }

Получение версии криптопро csp (метод getcspversion)

altCadesPlugin.getCSPVersion()
.then(function(version){
    version.major; // 4
    version.minor; // 0
    version.build; // 9630
    version.full; // 4.0.9630
});

Получение версии плагина (метод getversion)

altCadesPlugin.getVersion()
.then(function(version){
    version.major; // 2
    version.minor; // 0
    version.build; // 12245
    version.full; // 2.0.12245
});

Получение данных (метод get)

altCadesPlugin.get('CAdESCOM.About').then(function(aboutObject){
    В этом колбэке доступна переменная aboutObject, в которой хранится только что созданный объект
});

Получение списка сертификатов (метод getcertificates)

altCadesPlugin.getCertificates()
.then(function(certificates){
    certificates.subject; // владелец сертификата
    certificates.issuer; // издатель сертификата
    certificates.validFrom; // дата начала действия сертификата, дата выдачи
    certificates.validTo; // дата окночания действия сертификата
    certificates.algorithm; // алгоритм шифрования
    certificates.hasPrivateKey; // наличие закрытого ключа
    certificates.isValid; // валидность
    certificates.thumbprint; // слепок, хэш
    certificates.certificate; // объект сертификата
});

Получение цепочки данных (метод get)

altCadesPlugin.get('CAdESCOM.About', 'PluginVersion', 'MajorVersion').then(function(majorVersion){
    В этом колбэке доступна переменная majorVersion, в которой хранится major-версия плагина
});

При использовании нативной библиотеки код выглядел бы так:

var about = yield cadesplugin.CreateObjectAsync('CAdESCOM.About');
var pluginVersion = yield about.PluginVersion;
var majorVersion = yield pluginVersion.MajorVersion;

Пример проверяющего наличие расширения кода

Чтобы активировать объекты расширения Browser plug-in, необходимо подключить файл cadesplugin_api.js к странице.

Через HTML это можно сделать так:

Через JavaScript делают так:// Создание объектаcryptopro ЭЦП Browser plug-in varoStore =cadesplugin.CreateObject(«CAdESCOM.Store»); varoSigner =cadesplugin.CreateObject(«CAdESCOM.CPSigner»); var oPrivateKey =cadesplugin.CreateObject(«X509Enrollment.CX509PrivateKey»).

Согласно новому ГОСТу все владельцы ЭЦП обязаны использовать последнюю версию плагина, отвечающую требованиям безопасности ФСБ. Загрузка расширения на ОС Windows проходит в автоматическом режиме, а последующая настройка зависит от используемого браузера.

Работа с расширением в системах Unix требует скачивания и распаковки архивов, подходящих под битность ОС. Последующая настройка схожа с ОС Windows. Перед началом работы с плагином необходимо через демо-страницу ввести данные пользователя и сертификата ЭЦП.

Проверка криптопро эцп browser plug-in

  1. Перейдите по ссылке, чтобы проверить работу плагина.
  2. Должна открыться страница со всплывающим окном “Подтверждение доступа”.
  3. Нажмите кнопку “Да”, чтобы разрешить плагину операцию с ключами и сертификатами от имени пользователя. Предоставление разрешения позволит плагину найти сертификаты, установленные на устройстве или внешних носителях.
  1. Если плагин КриптоПро ЭЦП Browser plug-in установлен корректно, то вы увидите следующую информацию: “Плагин загружен”. Также будет отображаться версия плагина, название и версия криптопровайдера.
Читайте также:  Прописать сертификат закрытого ключа в реестр КриптоПро — mirAdmin

Установили КриптоПро ЭЦП Browser plug-in или, наоборот, столкнулись с проблемами?

Напишите о своем опыте в комментариях! Мы будем рады обратной связи.

Проверка подписи криптопро

Чтобы проверить ЭЦП, необходимо воспользоваться специальным сервисом компании «КриптоПро»:

  1. Перейти на сервис КриптоПро DSS.
  2. Нажать «Выбрать» и указать путь к нужному документу.
  3. Указать «Проверка требований к квалифицированному сертификату», если того требует формат подписи.
  4. Система обработает документ представит результат проверки ЭЦП КриптоПро.

Представленный для проверки сервис бесплатный и не требует предварительной регистрации ЭЦП.

Процесс настройки

Дальнейшая настройка браузера зависит от используемой программы. Для IE дополнительные настройки не требуются, и сразу после установки и перезагрузки можно оценить корректность работы плагина. Для этого нужно в открывшейся форме разрешить операцию:

Если ошибок нет и установка прошла успешно, то система выдаст сообщение:

Проверка корректности работы плагина обязательна, т.к. без нее невозможно оценить готовность плагина к формированию ЭЦП.

Системные требования

  • Установка плагина возможна на следующих операционных системах:  Win XP SP3, Win Vista SP2, Win 2003 SP2, Win 2008 SP2, Win 7, Win 2008 R2, Win 8, Win8.1, Win10.
  • Работает с браузерами: IE 8 — 11, Opera, Mozilla Firefox, Google Chrome, Yandex Browser

           Не работает в браузере EDGE, предустановленном по умолчанию в Windows 10.

  • Требуется предустановленная КриптоПро CSP версии не ниже 3.6 R2

Следующим шагом инициализировать

altCadesPlugin.nonNpapiInit()
.then(function(){
    Следующий код уже будет в колбэках промисов
    ...
});

Установка и настройка крипто про эцп браузер плагин

ПО CryptoPro корректно работает с большинством интернет-обозревателей, поддерживающих выполнение сценариев на языке JavaScript. В их числе:

  • Opera;
  • Yandex;
  • Internet Explorer;
  • Mozilla Firefox;
  • Chrome.

Перед установкой приложения убедитесь в том, в  операционной системе для вас включены права администратора, а все приложения и документы закрыты. Далее действуйте согласно следующей инструкции:

  1. Найдите скачанный дистрибутив CadesPlugIn.exe — по умолчанию сохраняется в папку «Загрузки».
  2. Щелкните два раза по файлу.
  3. В окне активируйте опцию «Запустить».
  4. Подтвердите намерение установки ПО путем нажатия на кнопку «Да».
  5. Запустится инсталляция вспомогательных компонентов. По завершении процесса кликните «ОК» и перезапустите операционную систему.

Процесс настройки  Крипто Про ЭЦП Браузер плагин зависит от используемого интернет-обозревателя.

Установка плагина на unix

Работа с ЭЦП в системе Unix возможна с браузерами Firefox, Opera версии 35, Chromium, Chrome, а также Яндекс.

Электронная цифровая подпись на сайте при помощи криптопро эцп browser plug-in

В данной статье рассмотрим использование электронно-цифровой подписи на сайте.

Что необходимо, чтобы человек смог использовать электронно-цифровую подпись на сайте?

1) СКЗИ (средство криптографической защиты информации)
Мой опыт работы показывает, что порядка 90% использует КриптоПро CSP (скачать), который в явном или неявном виде продвигают удостоверяющие центры. Порядка 10% VipNet CSP (), который можно использовать бесплатно. С остальными СКЗИ на практике не встречался.
2) КриптоПро ЭЦП Browser plug-in (страница плагина).
3) Установленная подпись (хотя бы одна).

Проверка возможности осуществления подписи
javascript ( jquery)

1) Попытка создать объект cades.
Нужно сделать примечание, что тут и далее, будет деление на браузер с ActiveX(читай IE) и остальные.
Проверка будет осуществляться:

return ('ActiveXObject' in window);

для ActiveX:

try {
    store = new ActiveXObject('CAdESCOM.store');
    status = true;
} catch (e) {
    status = false;
}

Для остальных:

if (navigator.mimeTypes['application/x-cades']) {
    status = true;
} else {
    status = false;
}

Если проверка прошла неудачно, то уведомляем об этом пользователя.

Стоит иметь ввиду, что после обновления хрома до версии 42 (спасибо

статье

за информацию) нужно включить:

chrome://flags/#enable-npapi

Следующая проверка — а разрешен ли плагин для запуска (не для IE проверка)?

try {
    store = objSign.CreateObject('CAPICOM.store');
    status = true;
} catch (e) {
    status = false;
}

Где objSign:

objSign = $('<object/>', {
    'id': 'cadesplugin',
    'type': 'application/x-cades',
    'css': {
        'visibility': 'hidden',
        'height': '0px',
        'width': '0px',
        'position': 'absolute'
    }
}).appendTo('body').get(0);

Проверяем на СКЗИ путем попытки открыть хранилище.

try {
    store.Open();
    status = true;
} catch (e) {
    status = false;
}

Проверяем на существование сертификатов в хранилище:

if ('Certificates' in store) {
    certs = store.Certificates;
}

И их количество (бывает, что Certificates есть, но пуст, что нам тоже не подойдет):

if (certs.Count) {
    status = true;
} else {
    status = false;
}

Первый шаг сделали — проверили возможность подписания чего-либо.

Выбор электронной цифровой подписи

У клиента может быть установлено несколько сертификатов. Сертификаты могут быть от разных удостоверяющих центров (УЦ), выданными быть разным людям, с разными датами выдачами, поэтому надо предоставить выбор, каким именно он хочется воспользоваться.

1) Группируем по удостоверяющим центрам
Информация об удостоверяющем центре хранится в сертификате.

certs.Item(i).GetInfo(1)
где certs — сертификаты из хранилища, см выше
i — порядковый номер сертификата от 1 (обратите внимание) до certs.Count.
Обратите внимание, что, в случае «кривых» сертификатов, вернуться может и undefined, имеет смысл сделать один дефолтный УЦ для таких случаев.

Теперь мы знаем список УЦ, услугами которых воспользовался клиент.
Запоминаем их и выведем через optgroup.
Сам text у option будет таким:

cert.GetInfo(6)   ' ('   formatDate(cert.ValidFromDate)   ' - '   formatDate(cert.ValidToDate)   ')'

в

cert.GetInfo(6)

— кому выдан сертификат

в

ValidFromDate

— с какого срока сертификат начал/начнет действие

в

ValidToDate

— соответственно, до какого срока

Ну и форматирование даты стандартное:

function formatDate(d) {
    try {
        d = new Date(d);
        return ('0'   d.getDate()).slice(-2)   '.'   ('0'   (d.getMonth()   1)).slice(-2)   '.'   d.getFullYear();
    } catch (e) {
        return '';
    }
}

Еще можно подсветить option.

Зеленым — для работоспособных сертификатов, красным — нет.

Информацию можно получить при помощи самого сертификата.

try {
    return cert.IsValid().Result;
} catch (e) {
    return false;
}

Стоит отметить, что сама по себе данная проверка имеет малую ценность, ибо все причины не может отсечь.

Но самые базовые, например, проверка даты — проверяет.

В value у option запишем отпечаток cert.Thumbprint.
Можно порядковый номер записать, можно другие данные — на ваше усмотрение.

Подписание
Ну и, собственно, самый главный шаг, к которому мы стремились — подписание.

1) Находим выбранный сертификат.
Для нашего примера:

certs.Find(0, thumbprint).Item(1)

0

— означает, что мы ищем по отпечатку

1

— что используем первый результат выборки (по факту единственный)

2) Подписываем:

if (isActiveX()) {
    var CPSigner = new ActiveXObject('CAdESCOM.CPSigner');
} else {
    var CPSigner = objSign.CreateObject('CAdESCOM.CPSigner');
}
CPSigner.Certificate = cert;
if (isActiveX()) {
    var SignedData = new ActiveXObject('CAdESCOM.CadesSignedData');
} else {
    var SignedData = objSign.CreateObject('CAdESCOM.CadesSignedData');
}
SignedData.Content = text;
return SignedData.SignCades(CPSigner, 1, false);

где cert — сертификат, при помощи которого подписываем
text — собственно, что подписываем
Ну а в return возвращается подписанное сообщение.

p.s. По максимуму код постарался вычистить от специфики проекта. Если кому-то этот материал пригодится и будет интересно — напишу и серверную часть. Проверка подписанного сообщения (с цепочкой и без), проверка сертификата (ocsp и без), использования tsp и т.д.

Яндекс.браузер

Настройка в Яндекс.Браузере проходит наиболее быстро. Выполните следующие шаги:

  1. Запустите интернет-обозреватель.
  2. Кликните по иконке с тремя черточками — находится вверху справа.
  3. В меню щелкните по строке «Дополнения».

Откроется страница, которую нужно прокрутить в самый низ. Напротив ранее инсталлированного ПО нажмите «Включить».

Вам будет интересно: Плагин ЭЦП от КриптоПро: обзор, установка

Оцените статью
ЭЦП Эксперт
Добавить комментарий