Как стать автором
Обновить
23
0
Василий Бурмистров @vburmistrov

Пользователь

Отправить сообщение

Здравствуйте!
Совершенно верно, манипуляции с библиотекой itextpdf_patched-5.1.3.jar крайне сомнительны с точки зрения прохождения проверок регуляторов и в случае разбора конфликтных ситуаций. Но статье 6 лет. С тех пор появилась библиотека itextpdf_patched-5.5.5.jar, которую включают в состав сборок КриптоПро JavaCSP. Надеюсь там ни чего патчить уже не надо, но сам я не проверял. PDF подпись так и осталась мало популярной для использования в автоматизированных системах.

Мне тоже сразу вспоминается статья про положение дел на фронте: Каково оно учить JavaScript в 2016 :-)
Вот так и собираем информацию по крупицам из разных не всегда даже полуофициальных источников. Все так запутано с правами и авторством, что простому пользователю крайне сложно разобраться.
Причём AES имеет немного запятнанную репутацию, потому что криптографы говорят следующее:


Кто-то редактировал наш сегмент ru.wikipedia.org/wiki/Triple_DES и сообщил следующее:

Тем не менее, 3DES понемногу выходит из употребления: на смену ему приходит новый алгоритмом AES Rijndael. Rijndael, реализованный программно, работает в шесть раз быстрее. Поэтому 3DES больше подходит для аппаратных реализаций. Многие системы безопасности продолжают поддерживать как 3DES, так и AES, по умолчанию используя AES. Хотя 3DES может поддерживаться для обратной совместимости, он больше не рекомендован к использованию.


Все же, что сейчас предпочтительнее в разработке применять?
Только все-таки:
JaCarta PKI — сертифицированные USB-токены и смарт-карты с аппаратной реализацией зарубежных криптоалгоритмов


Криптография есть, но зарубежная. Что позволяет:

безопасно хранить пользовательские данные и ключевые контейнеры популярных программных средств криптографической защиты информации (СКЗИ)

Здравствуйте!

По пункту 2, да, для JaCarta достаточно — cprocsp-rdr-jacarta.
Другие пакеты оставил исключительно для иллюстрации:
cprocsp-rdr-novacard-64-4.0.9944-5.x86_64.rpm
cprocsp-rdr-mskey-64-4.0.9944-5.x86_64.rpm

Спасибо за уточнения!
Это не совсем корректная информация. Ключи eToken Pro Java продаются и поддерживаются компанией Gemalto. Более того, линейка развивается и выходят новые версии ключей: habr.com/ru/post/281256


Токен, который у нас оказался SafeNet, был куплен в Аладдин Р.Д. Есть номер договора, дата и партия, в которой он состоял.
Первоначально возникло недоразумение, все считали, в том числе поддержка Аладдин Р.Д., что он JaCarta PKI, а факты работы с ним через SAC Tools, а не IDProtect, доказали обратное. И на тот момент он был уже в опломбированном сервере в удаленном ВЦ.

Middleware, наверное, всё же лучше запрашивать у производителя или официального дистрибутора продуктов Gemalto.


Разумное утверждение.

Мы и запросили там, где покупали — у официального дистрибьютора продуктов Gemalto, которым был Аладдин Р.Д вплоть до 1 декабря 2017 года, согласно информации на сайте Аладдин Р.Д
Так тут все просто. В общем виде сохранить Java сериализованный ключ можно так:

   FileOutputStream fos = new FileOutputStream(new File("key.pem"));
   fos.write(Base64.encodeToByte(privateKey.getEncoded(), false));
   fos.close();


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

Если надо куда-то скопировать, экспортировать ключи, то лучше это сделать руками в СКЗИ.

В ПО наоборот надо позаботиться о безопасности ключа и пароля от контейнера. Пароль разделяем, шифруем и прячем. Склеиваем, расшифровываем пароль в потоке для одноразового чтения, извлекаем ключ и храним в памяти доли секунды для непосредственного использования.
Уважаемый, Владимир Николаевич!
Во первых не JavaCarta, а JaCarta.

Вы с представленным руководством ознакомились? Цель и тема его несколько иная.

Во вторых я бы не хотел дополнительно рекламировать продукцию организации, выпускающей эти токены. А ответы на интересующие Вас вопросы Вы можете найти у них на сайте и в отделе продаж.
Не совсем понимаю, что именно ищете в данном руководстве про PKCS#11
Чтобы работать с токенами в КриптоПро CSP устанавливается модуль поддержки cryptographic token interface:
lsb-cprocsp-pkcs11-64 | CryptoPro PKCS11

Токены JaCarta аппаратно поддерживают новые российские криптографические алгоритмы ГОСТ Р 34.10-2012 и ГОСТ Р 34.11-2012
Заголовок обобщенный. Речь идет о токенах с поддержкой интерфейса PKCS#11 и российской криптографии на них. Руководство так же косвенно может помочь настроить работу с флэшкой и поместить на нее HDIMAGE программный контейнер с ключами.
Пожалуй просто оставлю вот это здесь.
Оно в тему, да и самому иногда полезно зайти и освежить в памяти :-)

Это пример, как используя java.net.HttpURLConnection поднять TLS ГОСТ защищенное соединение со стороны клиента.

Создаем ГОСТ-овый SSLContext:
package ru.alfabank.example.tls;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.lang.exception.ExceptionUtils;

import ru.alfabank.ccjava.example.exceptions.TLSGostContextException;
import ru.alfabank.ccjava.example.rest.ExampleService;

public class TLSGostContext {
    
    private static final String PRIVATE_KEY_NOT_FOUND = "privateKey not found! ";
    private static final String TLS_GOST_CONTEXT_EXCEPTION = "TLSGostContextException: ";
    private static final Logger LOGGER = Logger.getLogger(TLSGostContext.class.getName());
    private static final char[] PASSWORD = "123456".toCharArray();
    private static final String SIGNER_KEY_ALIAS = "vburmistrov";
    
    public SSLContext getContext() throws TLSGostContextException {
        
        SSLContext context = null;
        try {
            System.setProperty("ru.CryptoPro.reprov.enableCRLDP", "true");
            System.setProperty("com.sun.security.enableCRLDP", "true");
            
            System.setProperty("ssl.KeyManagerFactory.algorithm", "GostX509");
            System.setProperty("javax.net.ssl.keyStoreType", "HDIMAGE");
            System.setProperty("javax.net.ssl.keyStorePassword", "123456");
            
            KeyStore trustStore = KeyStore.getInstance("JKS");
            trustStore.load((FileInputStream) ExampleService.class.getClassLoader().getResource("data/trustStore.jks").openStream(), PASSWORD);
            
            KeyStore keyStore = KeyStore.getInstance("HDIMAGE", "JCSP");
            keyStore.load(null, PASSWORD);
            
            X509Certificate cert = (X509Certificate) keyStore.getCertificate(SIGNER_KEY_ALIAS);
            LOGGER.info("Signer found: " + ((X509Certificate) cert).getSubjectX500Principal().getName());
            
            PrivateKey privateKey = null;
            Key key = keyStore.getKey(SIGNER_KEY_ALIAS, PASSWORD);
            if (key != null) {
                privateKey = (PrivateKey) key;
            } else {
                LOGGER.log(Level.WARNING, PRIVATE_KEY_NOT_FOUND + SIGNER_KEY_ALIAS);
                throw new TLSGostContextException(PRIVATE_KEY_NOT_FOUND + SIGNER_KEY_ALIAS);
            }
            
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("GostX509", "JTLS");
            kmf.init(keyStore, PASSWORD);
            
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("GostX509", "JTLS");
            tmf.init(trustStore);
            
            context = SSLContext.getInstance("GostTLS", "JTLS");
            context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            
        } catch (KeyStoreException | NoSuchProviderException e) {
            LOGGER.log(Level.INFO, TLS_GOST_CONTEXT_EXCEPTION + ExceptionUtils.getFullStackTrace(e));
            throw new TLSGostContextException(e);
        } catch (NoSuchAlgorithmException e) {
            LOGGER.log(Level.INFO, TLS_GOST_CONTEXT_EXCEPTION + ExceptionUtils.getFullStackTrace(e));
            throw new TLSGostContextException(e);
        } catch (CertificateException e) {
            LOGGER.log(Level.INFO, TLS_GOST_CONTEXT_EXCEPTION + ExceptionUtils.getFullStackTrace(e));
            throw new TLSGostContextException(e);
        } catch (IOException e) {
            LOGGER.log(Level.INFO, TLS_GOST_CONTEXT_EXCEPTION + ExceptionUtils.getFullStackTrace(e));
            throw new TLSGostContextException(e);
        } catch (UnrecoverableKeyException e) {
            LOGGER.log(Level.INFO, TLS_GOST_CONTEXT_EXCEPTION + ExceptionUtils.getFullStackTrace(e));
            throw new TLSGostContextException(e);
        } catch (KeyManagementException e) {
            LOGGER.log(Level.INFO, TLS_GOST_CONTEXT_EXCEPTION + ExceptionUtils.getFullStackTrace(e));
            throw new TLSGostContextException(e);
        } catch (Exception e) {
            LOGGER.log(Level.INFO, TLS_GOST_CONTEXT_EXCEPTION + ExceptionUtils.getFullStackTrace(e));
            throw new TLSGostContextException(e);
        }
        return context;
    }
    
}


В trustStore у нас должен быть корневой сертификат УЦ, от которого цепочка строится к клиентским TLS сертификатам с расширением «Проверка подлинности клиента (1.3.6.1.5.5.7.3.2)»
Я на всякий случай положил туда и сертификаты промежуточных центров сертификации.

В keyStore у нас должны лежать ключи c клиентским сертификатом и в обязательном порядке вся цепочка до коневого УЦ.

Далее используя созданный SSL контекст, открываем HttpsURLConnection:
 private HttpsURLConnection openConnection(URL serverAddress, String method) throws IOException, TLSGostContextException {
        HttpsURLConnection connection;
        //Set up the initial connection
        connection = (HttpsURLConnection) serverAddress.openConnection();
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("Keep-Alive", "header");
        connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
        connection.setRequestMethod(method);
        connection.setDoOutput(true);
        connection.setReadTimeout(300000);
        connection.setSSLSocketFactory(new TLSGostContext().getContext().getSocketFactory());
        return connection;
    }


Далее, все как обычно, готовим тело HTTPS запроса, подключаемся, отправляем его на сервер и читаем ответ:
  try {
                    URL serverAddress = null;
                    
                    serverAddress = new URL(WORK_SERVER_URL);
                    
                    //  connection = openSimpleConnection(serverAddress, "POST");
                    connection = openConnection(serverAddress, "POST");
                    
                    FileInputStream fis1 = (FileInputStream) ExampleService.class.getClassLoader().getResource("data/req.xml").openStream();
                    
                    ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
                    byte[] dataBase64bytes1 = new byte[1024];
                    int len1;
                    while ((len1 = fis1.read(dataBase64bytes1)) != -1) {
                        baos1.write(dataBase64bytes1, 0, len1);
                    }
                    
                    byte[] dataBytes = baos1.toByteArray();
                    String xmlString = new String(dataBytes, "UTF-8");
                    System.out.println("Send packet: " + xmlString);
                    
                    DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
                    dos.write(dataBytes);
                    dos.flush();
                    
                    connection.connect();
                    
                    BufferedReader br = null;
                    sb = new StringBuilder();
                    
                    String line;
                    try {
                        
                        br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                        while ((line = br.readLine()) != null) {
                            sb.append(line);
                        }
                        
                    } catch (IOException e) {
                        String connectionResponseMessage = connection.getResponseMessage();
                        System.out.println("ERROR!!! " + connectionResponseMessage);
                        br = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
                        while ((line = br.readLine()) != null) {
                            sb.append(line);
                        }
                        builder = Response.ok().entity(sb.toString().getBytes());
                        builder.build();
                        e.printStackTrace();
                    } finally {
                        if (br != null) {
                            try {
                                br.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    
                    System.out.println("RESULT: " + sb.toString());
                    
                } catch (IOException e) {
                    LOGGER.log(Level.INFO, "ERROR!!! " + ExceptionUtils.getFullStackTrace(e));
                    throw new RuntimeException(e);
                } catch (TLSGostContextException e) {
                    throw new RuntimeException(e);
                } catch (Exception e) {
                    LOGGER.log(Level.INFO, "ERROR!!! " + ExceptionUtils.getFullStackTrace(e));
                    throw new RuntimeException(e);
                } finally {
                    //close the connection, set all objects to null
                    connection.disconnect();
                    connection = null;
                }


В итоге при включенном расширенном логировании Включение журналирования КриптоПро JTLS, мы видим всю процедуру проверки ключей и рукопожатия сервера и клиента:
[0m[32m2018-08-29 17:49:51,730 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Certificate request received.
[0m[32m2018-08-29 17:49:51,731 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Search for client containers with GOST algorithms.
[0m[32m2018-08-29 17:49:51,731 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Search for client containers with type: GOST3410_2012_512
[0m[32m2018-08-29 17:49:51,731 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% getting aliases for Client
[0m[32m2018-08-29 17:49:51,731 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% check public key algorithm
[0m[33m2018-08-29 17:49:51,732 WARNING [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% No alias is match
[0m[32m2018-08-29 17:49:51,732 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Containers not found.
[0m[32m2018-08-29 17:49:51,732 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Search for client containers with type: GOST3410_2012_256
[0m[32m2018-08-29 17:49:51,732 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% getting aliases for Client
[0m[32m2018-08-29 17:49:51,732 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% check public key algorithm
[0m[33m2018-08-29 17:49:51,732 WARNING [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% No alias is match
[0m[32m2018-08-29 17:49:51,732 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Containers not found.
[0m[32m2018-08-29 17:49:51,732 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Search for client containers with type: GOST3410EL
[0m[32m2018-08-29 17:49:51,733 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% getting aliases for Client
[0m[32m2018-08-29 17:49:51,733 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% check public key algorithm
[0m[32m2018-08-29 17:49:51,733 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% check extended key usage. size: 14
[0m[32m2018-08-29 17:49:51,733 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) %% check extended key usage of Client
[0m[32m2018-08-29 17:49:51,734 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) matching alias: vburmistrov
[0m[32m2018-08-29 17:49:51,734 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Check private key: vburmistrov
[0m[32m2018-08-29 17:49:51,734 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Certificate chain vburmistrov found. Check if DH available…
[0m[32m2018-08-29 17:49:51,734 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Private key vburmistrov is available. Test key…
[0m[32m2018-08-29 17:49:51,735 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) tls_client_fixed_DH state not allowed. Use cached key vburmistrov
[0m[32m2018-08-29 17:49:51,735 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) Use cached key and certificate with alias vburmistrov
[0m[32m2018-08-29 17:49:51,736 FINE [ru.CryptoPro.ssl.SSLLogger] (default task-6) *** Certificate message
chain [0] = [
[
Version: V3
Subject: SURNAME=Бурмистров, GIVENNAME=Василий ТЕСТ, T=Тестовое, CN=Альфабанк ТЕСТ, O=Альфабанк ТЕСТ, L=Москва, ST=77 г. Москва, C=RU, EMAILADDRESS=test@test.ru, OID.1.2.643.3.131.1.1=#120C303031313131313131313131, OID.1.2.643.100.1=#120D31313131313131313131313131, OID.1.2.643.100.3=#120B3131313131313131313131, OID.1.2.840.113549.1.9.2=«INN=1111111111/KPP=111111111/OGRN=1111111111111»
Signature Algorithm: 1.2.643.2.2.3, OID = 1.2.643.2.2.3

Key: 1.2.643.2.2.19
Validity: [From: Wed Aug 22 10:29:39 MSK 2018,
To: Thu Aug 22 10:39:39 MSK 2019]
Issuer: CN=«ООО \»Ромашка\"", O=«ООО \»Ромашка\"", OU=Отдел информационной безопасности, L=Москва, ST=77 г.Москва, C=RU, OID.1.2.643.3.131.1.1=#120C303037373037373532323330, OID.1.2.643.100.1=#120D31313137373436343830333334
SerialNumber: [ 8dd25d85e811dea5 8dd25d85e811dea5 ]


Думаю, для отката должны быть припасены Git ветка productRelease с кодом ПО предыдущей версии, сборки обкатанных образов Docker в Artifactory, прочие необходимые настройки и артефакты и отдельный pipeline в Jenkins, который это развернет. В нашем проекте схема такая.

kruftik, спасибо за статью.
«Те, кто затевают эти блокировки, блокировки затевают, вот это вот это, затевают все вот это. Это я… Этим людям я это и адресовываю. Доиграетесь. С этими блокировками, которые вы затеваете.» :-)
Да, мне тоже сразу на ум пришли вопросы ИБ и защиты конфиденциальной информации компании от утечки по техническим каналам.
А что, половина работы сделана, коробочки установлены на легальных основаниях в согласованные места. Даже уборщица к ним привыкла.
Добавь туда виброакустический датчик для снятия речевой информации или еще лучше pinhole камеру. И батареек всем хватит. :-)
А вообще классно, прогресс не остановить.
m1ld, да плотная работа в этом направлении ведется.

— в документе Методические рекомендации по работе с ЕСМЭВ версия 3.4.0.3 есть термин Каталог типов данных и атрибутов (КТДА).

— создан специальный модуль Руководство пользователя Модуля «Каталог типов данных и атрибутов» (СМЭВ.КТДА), в ктоором уполномоченный пользователь может заводить и согласовывать новые атрибуты и посмотреть существующие утвержденные.

— разработана целая концепция для решения проблемы взаимодействия именно в части унификации набора согласованных и используемых сущностей Концепция по использованию КТДА
olegchir, а как же путь Бусидо́ 武士道

Путь воина, который без ропота вступит в противоборство с самым отвратительным API или его отсутствием и разберется со всеми сложностями?! :-)

Полезность здравой критики оспаривать не стану. :-)
Да. Под Open Source я имел в виду в широком понимании, например, Open-Source JDK — Oracle в части публичных классов и предоставляемых APIs и различные компоненты и библиотеки с лицензией свободного программного обеспечения.

Apache Kafka это конкретный инструмент со своим набором функций, tutorials и manuals, для которого тщательно обстругиваются сообществом.

С RabbitMQ у меня тоже сообщения за день начали ходить.

Другое дело, когда речь идет о целой распределенной инфраструктуре – Public Key Infrastructure.

Куда можно отнести СКЗИ и СМЭВ, как разные ее составные инструменты, компоненты, системы.

Инфраструктура с открытым ключом вбирает в себя технологии и знания из совершенно разных областей, с которыми требуется разбираться.

Начиная с наборов различных стандартов X. группы PKIX, стандартов криптографии PKCS#, способов описания структур данных на ASN.1 с древовидной идентификацией OID и наборов криптографических алгоритмов до принципов работы Центров регистрации и сертификации, протоколов взаимодействия, стандартов ЭП. И заканчивая Java Cryptography Architecture (если используем Java) и знаниями в области XML (для XMLDSig и СМЭВ) и инструментов для работы с ним применительно к платформе.

Дикая смесь и много чего еще, к которой добавляются описания и интерфейсы конкретных реализаций СКЗИ, СМЭВ, программно-аппаратных комплексов для УЦ и защиты и хранения ключей.

Поэтому временные затраты на то, чтобы разобраться не сопоставимы.
Класс SmevTransformSpi может дорабатываться, но набор правил трансформации, реализованных в нем, для конкретной версии схемы СМЭВ остается неизменным.
Здравствуйте, Олег!

Я читал Вашу статью про Побег из КриптоПро. Такое нельзя пропускать.
Безусловно мощно и полезно. Спасибо Вам!

Но есть одна загвоздка, когда дело касается промышленного общения через СМЭВ, то речь идет о квалифицированной ЭП, а значит, как одно из требований, выработанной на СКЗИ от разработчика лицензиата ФСБ. И тут не убежишь, предусмотрена ответственность.

В остальном для тестов и кейсов, что называется, для себя, то тут конечно можно достигнуть существенной экономии на лицензиях.

По поводу сложностей в использовании:
правильный способ — сделать такое SDK, которое бы своим API показывало, как решать типичные вопросы.


Это было бы идеально.

Но тут все усложняется тем, что лицензированный разработчик СКЗИ, например, КриптоПро — это одна организация, а ФГУП НИИ «Восход», на мощностях, которого подняты Головной удостоверяющий центр Минкомсвязь и СМЭВ — другая.

У каждой есть своя документация, SDK и API, примеры, форум, портал технической поддержки и ситуационный центр.
Причем есть конкретные примеры и инструкции, которые пересекаются, как например у КриптоПро для СМЭВ.

Информации, конечно, много, разобраться сложно, но можно.

Мне сразу вспоминается статья Каково оно учить JavaScript в 2016. Вот где зоопарк :-)

А вообще для разработчиков Open Source разбираться в чем-то таком должно доставлять какое-то свое особое удовольствие :-)
1

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Работает в
Дата рождения
Зарегистрирован
Активность