пятница, 25 сентября 2015 г.

Пример работы с SDK "Kalkan"

Так как меня не покидала уверенность в том что пример такой работы нужен остальным программистам которые используют  SDK "Kalkan",  я решил потратить часть своего времени на его создание. В дальнейшим по тексту вместо слова "пример" я буду использовать название проекта "Ldw-Example-Kalkan"  чтобы избежать любых неоднозначностей. Собственно сам  исходный  код можно скачать здесь.
Кода я писал "Ldw-Example-Kalkan" то держал в голове такие цели:
1) Приложение после получения его с гит-хранилища должно запускаться сразу, без какой либо дополнительной конфигурации.
2) Клиент запустив открыв "Ldw-Example-Kalkan" в браузере должен иметь возможность подписать произвольные данные с помощью апплета от НУЦ РК  и отправить  их на сервер для проверки.
3) Должна быть реализована на сервере "правильная проверка" подписи данных которые пришли с браузера клиента. Что же это такое "правильная проверка"? Это соответствие между моей реализацией программного кода и той бумажкой с требованиями которые прислал НУЦ РК.
4) Помимо "правильной проверки" есть дополнительные требования к проверке на сервере. Это возможность одновременной работы с ЭЦП разных версий и проверка БИНа или ИННа в ЭЦП. 
В дальнейшем статья состоит из того как мне удалось или не удалось достичь эти цели.

Цель 1. Конфигурация.
Приложение после получения его с гит-хранилища должно запускаться сразу, без какой либо дополнительной конфигурации.
Не получилось. В проекте используются некоторые либы и сертификаты из SDK "Kalkan" . Я не могу их включить в "Ldw-Example-Kalkan" так как НУЦ РК ограничивает их распространение.
Так что немножко придется потрудиться, коллега. У Вас должен быть SDK "Kalkan" на компе, чтобы запустить "Ldw-Example-Kalkan" в работу.
Путь к SDK "Kalkan" обозначим как "\PATH_SDK_Kalkan". Путь к папке где находиться проект  "Ldw-Example-Kalkan" обозначим "\PATH_EXAMPLE_Kalkan";
Для конфигурации "Ldw-Example-Kalkan" необходимо выполнить нижеследующие шаги как
а)  В локальный мавен-репозиторий необходимо добавить jar из SDK "Kalkan" : knca_provider_jce_kalkan.jar,  commons-logging-1.1.1.jar, xmlsec-1.4.4.jar
Перейдите в папку "\PATH_SDK_Kalkan\Java(Kalkan)\libs\" и выполните команды:
mvn install:install-file -Dfile=knca_provider_jce_kalkan-16.jar -DgroupId=kz.gov.pki -DartifactId=knca_provider_jce_kalkan -Dversion=1.1 -Dpackaging=jar

mvn install:install-file -Dfile=commons-logging-1.1.1.jar -DgroupId=kz.gov.pki.libs -DartifactId=commons-logging -Dversion=1.1.1 -Dpackaging=jar

mvn install:install-file -Dfile=xmlsec-1.4.4.jar -DgroupId=kz.gov.pki.libs -DartifactId=xmlsec -Dversion=1.4.4 -Dpackaging=jar

б) Скопируете файлы  "new_NCA_GOST.cer" и "new_NCA_RSA.cer"  из папки "\PATH_SDK_Kalkan\Keys and Certs\Текущий НУЦ (old oids)\CA Root Certs\"  в папку "\PATH_EXAMPLE_Kalkan\src\main\resources\kz\pki\ca\nuc1\"
в) Скопируете файлы  "rca_gost.crt" и "rca_rsa.crt"  из папки "\PATH _SDK_Kalkan\ Keys and Certs\Нового НУЦ (new oids)\ca\КУЦ\"  в папку "\PATH_EXAMPLE_Kalkan\src\main\resources\kz\pki\ca\ kuc\"
г) Скопируете файлы  "knca_root.crt" и "knca_rsa.crt"  из папки "\PATH _SDK_Kalkan\ Keys and Certs\Нового НУЦ (new oids)\ ca\НУЦ 2.0\"  в папку "\PATH_EXAMPLE_Kalkan\src\main\resources\kz\pki\ca\ kuc\"
д) ВАЖНО!  Так как хост на котором я писал пример находиться за прокси, то в коде я мне пришлось учитывать при получении списка отозванных ЭЦП.  
Если ваш хост работает БЕЗ прокси, то в классе com.lastdaywaiting.example.kalkan.service.SecureManager  исправите  константу DEFAUL_USE_PROXY на false.
Если ваш хост работает ЗА прокси, то в классе com.lastdaywaiting.example.kalkan.service.SecureManager  проставьте  константам DEFAUL_PROXY_ADDRESS  и  DEFAUL_PROXY_PORT нужные значения.
Другой вариант изменения этих настроек, это через свойства объекта. Так например:
SecureManager secure = new SecureManager(bin, name, respCode);
secure.setUseProxy( false );
secure.setProxyAddress( "192.168.1.1" );
secure.setProxyPort( 11111 );

Цель 2. "Ldw-Example-Kalkan" в  браузере.
Приложение "Ldw-Example-Kalkan" стандартное веб-приложение на платформе Spring framework. В нем всего одна страница на которой пользователь может последовательно выполнить ниже следующие шаги:
а) Ввести сообщение которое нужно подписать.
б) Загрузить апплет от НУЦ РК. В данный момент не все браузеры это могут сделать. Я тестировал все в IE. Я знаю только косвенные способы определения того что апплет  не загрузился, чтобы не усложнять пример я их не стал вставлять в javascript.
в) Выбрать нужное ЭЦП в формате файла p12 . Другие виды источников ЭЦП в примере не доступны, также с целью упрощения кода. Если Вам интересно работа сними, то смотрите пример в SDK "Kalkan", там все другие источники представлены (Казтокен , Личное Удостоверение, EToken Java 72k, AK JaCarta) .
г) Подписать сообщение выбранным ЭЦП. Не забудьте ввести пароль.
д) Отправить сообщение на проверку. Сообщение в формате JSON, которое будет отправлено на сервер для проверки, Вы можете изменить на той же страничке для целей тестирования. 
Каждый раз когда вы нажимаете любую кнопку на странице в верху страницы показывается результат выполненного действия:  Успешно или описание ошибки.

Цель 3. Проверка подписи на сервере.
Проверка подписи на сервере должна соответствовать  тем требованиям которые предъявляет к нам НУЦ РК. Опять наверное покажусь занудой, но мне не понравилось то как составили свои требования. Слишком кратко и непонятно что делать на мой взгляд. Все требования которые хотел от меня НУЦ РК реализованны  в классе com.lastdaywaiting.example.kalkan.service.SecureManager . Для проверки того хорошая это подпись или нет, надо вызвать метод isGoodSignature.  А всю остальную работу с JCE и т.д. пользователю метода знать не обязательно. 
Если все-таки Вы хотите взглянуть на реализацию более подробнее, то ниже приведены требования от НУЦ РК и методы которые их реализуют. Некоторые требования я посчитал не достаточно важными чтобы их реализовывать.  Но лучше всего для анализа конечно смотреть сам исходный код.
1) "Замена криптопровайдера в ИС"
Самый ясный пункт из всех. На сервере приложений надо использовать их новый криптопровайдер kz.gov.pki.kalkan.jce.provider.KalkanProvider
В примере этот пункт реализован в секций static #1 класса SecureManager.
            2) "Проверка электронной цифровой подписи"
В этом пункте  я  посчитал что требуется  убедиться в том, что данные присланные на сервер  - подпись  от этих данных  и сертификат которым подписывали данные совпадают.
В примере этот пункт реализован в методе reCheckClientSignature класса SecureManager.
3) " Проверка построения корректной цепочки от проверяемого регистрационного свидетельства до доверенного корневого регистрационного свидетельства удостоверяющего центра, с учетом промежуточных регистрационных свидетельств удостоверяющих центров;"
Тут есть не ясность в цепочке подписанных сертификатов "КУЦ->НУЦ2->ЭЦП респа". Зачем  проверять то что НУЦ2 был подписан сертификатом  КУЦ? Оба эти сертификата находятся в "Ldw-Example-Kalkan".  Я знаю что они правильные. Зачем еще одна проверка?  Я сделал эту проверку, но глубинный смысл её необходимости остался для меня сокрытым.
В примере этот пункт реализован в методах checkNucOneCertificateType для ЭЦП НУЦ 1 и checkNucTwoCertificateType для ЭЦП НУЦ 2  класса SecureManager.

4) " Проверка срока действия регистрационного свидетельства. Проверка сроков действия от проверяемого регистрационного свидетельства до доверенного корневого регистрационного свидетельства удостоверяющего центра, с учетом промежуточных регистрационных свидетельств удостоверяющих центров;"
Код проверки размазан по методам reCheckClientSignature для проверки ЭЦП респа и методам  checkNucOneCertificateType для сертификата НУЦ 1 и checkNucTwoCertificateType для сертификата НУЦ 2 .
            5) Проверка регистрационного свидетельства на аннулирование. Проверка регистрационного свидетельства на аннулирование осуществляется одним из методов:
на основе СОРС НУЦ РК. Данный метод проверки подтверждает, аннулировано ли проверяемое регистрационное свидетельство на момент начала срока действия СОРС НУЦ РК;
онлайн проверка регистрационного свидетельства на аннулирование, основанная на протоколе OCSP (On-lineCertificateStatusProtocol). Данный метод проверки подтверждает, аннулировано ли проверяемое регистрационное свидетельство на момент отправки запроса (текущее время);
на основе дополнительного СОРС. Данный сервис необходимо использовать совместно с сервисом СОРС, что позволяет получить более актуальную информацию, чем в сервисе СОРС. Данный метод проверки подтверждает, аннулировано ли проверяемое регистрационное свидетельство на момент начала срока действия дополнительного СОРС НУЦ РК
Здесь на выбор предоставляют три возможности для проверки отозваности. Я выбрал первый. Это загрузка CRL файлов из инета и проверка по ним.  Загрузка CRL- файлов происходит не всегда а через определенный период (константа HOURS_OF_RELOAD) . После загрузки CRL-файлов , они сидят в кэше.
В примере этот пункт реализован в методах isNotRevokedCertNucOne для ЭЦП от НУЦ 1 и isNotRevokedCertNucTwo для ЭЦП от НУЦ 2.
6) Проверка области использования ключа. Проверка заключается в проверке значения поля регистрационного свидетельства «использование ключа» (KeyUsage). Если поле «использование ключа» содержит значения «Цифровая подпись» и «Неотрекаемость», то это регистрационное свидетельство используется для ЭЦП. А если поле «использование ключа» содержит значения «Цифровая подпись» и  «Шифрование ключей», то это регистрационное свидетельство используется для аутентификации;
В примере этот пункт реализован в методе  isBadKeyUsage.  В нашем примере нужна только подпись. Так что проверяем наличие свойства «Неотрекаемость».
7) Проверка номера политики регистрационного свидетельства и разрешенных способах его использования. Если политика проверяемого регистрационного свидетельства предусматривает ограничение его использования (только в одной системе), то данное регистрационное свидетельство и соответствующий закрытый ключ не использоваться в других системах;
Не реализовано.
8) Проверка метки времени. Доказательством подписания документа в указанный момент времени является квитанция метки времени, полученная в НУЦ РК и содержащая время подписания документа. Данная проверка производится для электронных документов долговременного хранения и формируется в момент подписания документа;
Не реализовано.

9) Проверка полномочий  лица подписавшего документ. Механизмы проверки полномочий возлагаются на Систему.
Не реализовано.

Цель 4. Дополнительные проверки подписи на сервере.
Тут все относительно просто.  Эти требования которые я сам себе выдумал.
1)  Хотя в требованиях от НУЦ РК этого не сказано, но нам придется работать еще какое-то время  с сертификатами старого (НУЦ 1) и нового образца (НУЦ 2) . 
Поэтому в коде вначале сертификат проверяют на соответствие НУЦ 1 в методе checkNucOneCertificateType, а затем на соответствие НУЦ 2 в методе checkNucTwoCertificateType
2) В реальной системе  у меня пользователь заходит на сайт по протоколу HTTPS используя свой сертификат для аутентификаций на сайте. При подписаний используется другой сертификат и я хочу быть уверенным то что пользователь не ошибся в выборе сертификата. Это значит я знаю на момент проверки подписи какой БИН или ИИН должен быть сертификате подписавшем данные. Этот  БИН или ИИН я передаю в конструктор SecureManager.
Сама проверка проходит в методе isBadBinOrIin.  

PS1: К сожалению мне удавалось выделять достаточно свободного времени на этот проект. По причине почти полного отсутствия оного. Поэтому все затянулось.
PS2: Пока писал этот пример нашелся еще один человек который взял эту миссию на себя. Смотрите здесь.  У нас разные подходы, он писал либу для SDK "Kalkan",  я пример реализаций их требований. И возможно его подход будет для вас более удобным и понятным для использования SDK "Kalkan". Я не настаиваю.
PS3: Я тестил "Ldw-Example-Kalkan" только на сертификатах  юридических и физических лиц. Другие типы сертификатов (казначейство и нотариус)  работать скорее всего не будут.

 PS4: Вполне возможно что Вы найдете ошибки у меня. Как коде, так в этой статье. Просто я их еще не вижу. Если Вы их заметили , то дайте мне знать, плиз.

14 комментариев:

  1. Спасибо большое за подробный код.
    Когда планируете пункты 7, 8, 9 реализовать?
    Не совсем понятно, как проверять TSP, если будет время также напишите про это.
    Заранее спасибо

    ОтветитьУдалить
    Ответы
    1. Просите что не сразу ответил. Времени мне просто не хватает.
      По этой же причине, отсутствие свободного времени, я не планирую реализацию пунктов 7,8,9 в моем примере. Они не были нужны для работы моей системы и я не разбирался с ними. Специфика этих пунктов делает их необходимыми в банковских или трейдерских системах и это не мой случай.

      Удалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить
  3. Прочитал Ваш блог, и у меня появились пару вопросов к Вам. Я был бы очень рад если вы можете уделить мне пару минут и ответить на эти жизненно важные вопросы для меня.

    Я начинающий программист, и web-программирования для меня слишком далеко. Я пишу лабораторную работу, где у меня десктопное приложение написанное на java. Скачал sdk kalkan, добавил в свой проект, но не понимаю куда дальше идти.

    Суть лабораторной работы: Есть некоторый документ, его нужно подписать.
    Интерфейс в принципе самый простой : Button, FileChooser, и Флаг(true-когда проверен, false- если нет).

    Хочу узнать как используя библиотеку можна написать такое простое приложение.

    Заранее спасибо за уделенное мне время.

    ОтветитьУдалить
    Ответы
    1. Если у Вас есть вопросы по теорий того зачем, что и как подписывать то лично мне помогла эта старая статья о криптографий c Java 1.4 (http://www.ibm.com/developerworks/java/tutorials/j-sec1/j-sec1.html).
      По реализаций вашего примера, я думаю то как создать форму, элементы на ней, обработчики события для кнопки и то как прочитать файл в строку Вы должны знаете уже сами, а если нет то нагуглите примеры.
      По самому подписанию документа так это делается на клиенте. Для этого в SDK Kalkan есть пример ' knca_applet_example_is' - это html-страничка с JavaScript, который загружает их апплет и вызывает основные его функций в том числе и подписания. Вы можете запустить страничку у себя в браузере который поддерживает java-апплеты (FireFox поддерживает, Chrome уже нет) и поиграться с ней. JavaScript-код пример подписанию простого текста смотрите например в файле 'crypto_object.js' в функций signPlainData().
      Мой 'Пример работы с SDK "Kalkan"' относиться уже к проверки того что подписанный документ действительно подписан правильно и эта проверка происходит не на клиенте, а на сервере. Вам же в рамках лабораторной работы скорее всего будет достаточно просто показать то что вы умеете подписывать документы. Вам надо просто подключить себе в проект их knca_applet.jar и создать их MainApplet. Сигнатура вызовов методов их апплета будет той же что в их примере с JavaScript-кодом.
      Если что не понятно спрашивайте еще.

      Удалить
    2. Со стандартом гост одни проблемы, например pdf им не подпишешь, если получится подписать, то adobe reader его не откроет. Зачем наши его взяли не понятно, пользовались бы RSA, которым весь мир пользуется. Гост существует только в РФ, КЗ и пару других пост.совковых странах. Когда смотришь на эти либы, создается ощущение что его писали "специалисты" из РФ. Даже нашел переменную, которая называлась CryptoPro. Стало понятно откуда весь этот хлам.

      Удалить
  4. Этот комментарий был удален автором.

    ОтветитьУдалить
  5. Этот комментарий был удален автором.

    ОтветитьУдалить
  6. Спасибо большое Рустем! Ваш блог и сопутствующие материалы очень помогли (дабы не изобретать велосипед :)). Удачи!

    ОтветитьУдалить
  7. Не за что. Вам тоже успехов.

    ОтветитьУдалить
  8. Этот комментарий был удален автором.

    ОтветитьУдалить
  9. откуда могу скачать jar-файл (knca_provider_jce_kalkan)

    ОтветитьУдалить
    Ответы
    1. Ищите их в самой установленной программе NCALayer на вашем компе это будет где нибудь здесь, например : C:\Users\XXXXX\AppData\Roaming\NCALayer\ncalayer-cache\bundle2\version0.0\

      Удалить
  10. Здравствуйте! Хотел спросить как можно проверить на отозванный или действующий ЕЦП ключ, для этого нужен ШЭП или нет. Или просто нужен jar-файл (knca_provider_jce_kalkan). Библиотека kalkan у меня есть, просто не могу понять как это, это в самой библиотеке kalkan прописано, что мы кидаем подписанный xml, а он дальше смотрит как отозванный или действующий. Помогите пожалуйста!

    ОтветитьУдалить