Pull to refresh

Comments 3

К чему все эти громкие слова о шифровании, если HDImageStore — это просто папка с файлами (закрытыми ключами шифрования)? Т.е. любой пользователь на сервере может их скопировать.
mihmig, HDImageStore — это нативное хранилище СКЗИ КриптоПро, оно зашифровано и защищено паролем. Конечно, его надежность сильно проигрывает HSM модулям, тем более с неизвлекаемыми ключами, например, JaСarta.

А по поводу того, что любой пользователь может их скопировать с сервера. Так, во-первых, хранилище JKS или cacerts это тоже файлы. А во-вторых для защиты серверов обычно применяются организационные и технические меры защиты.
Пожалуй просто оставлю вот это здесь.
Оно в тему, да и самому иногда полезно зайти и освежить в памяти :-)

Это пример, как используя 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 ]


Sign up to leave a comment.