Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

2 Страницы12>
Опции
К последнему сообщению К первому непрочитанному
Offline evgen.p  
#1 Оставлено : 16 октября 2019 г. 11:19:27(UTC)
evgen.p

Статус: Участник

Группы: Участники
Зарегистрирован: 14.10.2019(UTC)
Сообщений: 13
Российская Федерация
Откуда: Екатеринбург

Сказал(а) «Спасибо»: 7 раз
Разрабатываю плагин на Кордову для возможности отправки запросов с клиента по TLS с ГОСТовскими сертификатами, односторонняя аутентификация. Для тестов использую https://cpca.cryptopro.ru/default.htm, также через curl получил сертификат для этого сайта.
Задача: используя полученный сертификат достучаться до сервера и получить от него ответ.
Мои действия:
  1. Проинициализировал провайдер
    Код:
    CSPConfig.initEx(context)

  2. Создал контейнер
    Код:
    trustStore = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
    trustStore.load(null, null);

    Пробовал создать так:
    Код:
    trustStore = KeyStore.getInstance(JCSP.HD_STORE_NAME, JCSP.PROVIDER_NAME);

    Возвращается ошибка
    Цитата:
    KeyStoreException: HDIMAGE not found

  3. Создал объект сертификата
    Код:
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    InputStream certInputStream = new ByteArrayInputStream(getSert().getBytes());
    Certificate certificate = certificateFactory.generateCertificate(certInputStream);

    Метод getSert() возвращает сертификат в текстовом виде. Вот он:

  4. Загрузил сертификат в контейнер
    Код:
    trustStore.setCertificateEntry("cpSert", certificate);

  5. Создаю контекст SSL
    Код:
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(Provider.KEYMANGER_ALG, Provider.PROVIDER_NAME);
    trustManagerFactory.init(trustStore);
    SSLContext sslContext = SSLContext.getInstance(Provider.ALGORITHM, Provider.PROVIDER_NAME);
    sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

  6. Пытаюсь подключиться
    Код:
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    
            URL url = new URL("https://cpca.cryptopro.ru/default.htm");
            String host = url.getHost();
            int port = url.getPort();
            SSLSocket sslSocket = null;
    
            if (port <= 0) {
                port = url.getDefaultPort();
            }
    
            try {
                sslSocket = (SSLSocket) sslSocketFactory.createSocket(host, port);
    
                InputStream inputStream = sslSocket.getInputStream();
                OutputStream outputStream = sslSocket.getOutputStream();
    
                String request = "GET /" + url.getFile() + " HTTP/1.0" + HTTP_HEADER_SEPARATOR;
    
                outputStream.write(request.getBytes());
                outputStream.flush();
            } finally {
                if (sslSocket != null) {
                    try {
                        sslSocket.close();
                    } catch (Exception e) {
                        // ignore
                    }
                } // if
            }

    И здесь, в 20й строке, вываливается исключение
    Цитата:
    javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty


Вопрос: дело в неверном алгоритме, типах хранилища/сертификата, в самом сертификате, или в сервере? Что ещё требуется для подключения к серверу, и в чём у меня может быть ошибка?

Отредактировано пользователем 29 октября 2019 г. 10:00:09(UTC)  | Причина: Не указана

Offline Андрей Солдатов  
#2 Оставлено : 16 октября 2019 г. 13:33:23(UTC)
Андрей Солдатов

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 12.03.2019(UTC)
Сообщений: 326
Мужчина
Российская Федерация
Откуда: Москва

Сказал «Спасибо»: 5 раз
Поблагодарили: 69 раз в 65 постах
Добрый день.
Посмотрите samples-sources.jar -> JTLS_samples -> ClientSample из состава дистрибутива.
Там есть пример односторонней аутентификации TLS клиента.
Техническую поддержку оказываем тут.
Наша база знаний.
Offline evgen.p  
#3 Оставлено : 16 октября 2019 г. 14:04:25(UTC)
evgen.p

Статус: Участник

Группы: Участники
Зарегистрирован: 14.10.2019(UTC)
Сообщений: 13
Российская Федерация
Откуда: Екатеринбург

Сказал(а) «Спасибо»: 7 раз
Автор: Андрей Солдатов Перейти к цитате
Добрый день.
Посмотрите samples-sources.jar -> JTLS_samples -> ClientSample из состава дистрибутива.
Там есть пример односторонней аутентификации TLS клиента.


Смотрю указанный Вами пример, в нём используется класс TLSContext. В приложении я не смог найти примеров его использования, и в проект он не импортится. Может это быть из-за того, что у нас используется версия не android-csp-5.0.40424, а android-csp-5.0.40350? Можете скинуть ссылку на документацию, где этот класс описан, или пример в коде?

UPD: вместо TLSContext использовал следующий код, чтобы создать экземпляр SSLSocketFactory:
Код:

        String urlPath = "https://www.cryptopro.ru/certsrv/certcarc.asp";
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                ru.CryptoPro.ssl.android.Provider.KEYMANGER_ALG,
                ru.CryptoPro.ssl.android.Provider.PROVIDER_NAME
        );

        // Загрузка контейнера
        KeyStore trustStore = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
        //File appKeyStoreFile = new File(context.getFilesDir(), "AbKeyStore");
        //FileInputStream appKeyStoreInputStream = new FileInputStream(appKeyStoreFile);
        trustStore.load(null, null);

        // Создание объекта сертификата
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        InputStream certInputStream = new ByteArrayInputStream(hexStringToByteArray(getSert()));
        Certificate certificate = certificateFactory.generateCertificate(certInputStream);



        // Загрузка сертификата в контейнер
        trustStore.setCertificateEntry("cpSert", certificate);
        trustManagerFactory.init(trustStore);
        SSLContext sslContext = SSLContext.getInstance(
                ru.CryptoPro.ssl.android.Provider.ALGORITHM,
                Provider.PROVIDER_NAME
        );
        sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
        SSLSocketFactory factory = sslContext.getSocketFactory();

        connect(factory, urlPath);

Теперь вылетает
Цитата:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: [PKIX] a failure during build of the certificate chain

Метод getSert() теперь возвращает сертификат в виде hex строки, сгенерированный тут: https://www.cryptopro.ru/certsrv/certcarc.asp
Я на том же ресурсе генерировал цепочку, но внутри там только один сертификат, вот этот: http://joxi.ru/Y2LRpgJH7pDpwr
Можете подсказать, какие действия требуются для установления с сервером соединения с односторонней аутентификацией? Тот пример, который Вы предложили, невозможно воспроизвести. Может быть расскажете подробнее механизм подключения? И тогда станет понятно, где ошибка?

Отредактировано пользователем 17 октября 2019 г. 7:42:34(UTC)  | Причина: Не указана

Offline Андрей Солдатов  
#4 Оставлено : 17 октября 2019 г. 10:25:12(UTC)
Андрей Солдатов

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 12.03.2019(UTC)
Сообщений: 326
Мужчина
Российская Федерация
Откуда: Москва

Сказал «Спасибо»: 5 раз
Поблагодарили: 69 раз в 65 постах
Автор: evgen.p Перейти к цитате

Смотрю указанный Вами пример, в нём используется класс TLSContext. В приложении я не смог найти примеров его использования, и в проект он не импортится.
Может это быть из-за того, что у нас используется версия не android-csp-5.0.40424, а android-csp-5.0.40350? Можете скинуть ссылку на документацию, где этот класс описан, или пример в коде?


В любом случае - используйте последнюю сертифицированную сборку Android CSP.
Класс TLSContext есть в библиотеке cpSSL-android.

Для односторонней аутентификации необходимо в указанном мною примере необходимо передать в trustStore цепочку сертификатов веб-сервера.
Техническую поддержку оказываем тут.
Наша база знаний.
thanks 1 пользователь поблагодарил Андрей Солдатов за этот пост.
evgen.p оставлено 17.10.2019(UTC)
Offline Евгений Афанасьев  
#5 Оставлено : 17 октября 2019 г. 11:16:37(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 3,906
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 684 раз в 645 постах
Добрый день.

KeyStoreException: HDIMAGE not found - скорее всего, не был добавлен провайдер JCSP в Security.addProvider() и другие провайдеры. Помимо CSPConfig.init, надо вызвать еще несколько функций (см. MainActivity в ACSPClientApp - ф. initJavaProviders()).

javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty - вероятно, в хранилище добавлен(ы) сертификаты не корневые (самоподписанные), а серверные. Нужны корневые сертификаты.

"в нём используется класс TLSContext. В приложении я не смог найти примеров его использования, и в проект он не импортится" - скорее всего, в указанных библиотеках еще нет TLSContext.

"javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: [PKIX] a failure during build of the certificate chain" - не удалось построить цепочку сертификатов. Предполагаю, что не строится цепочка другой стороны (сервера), т.к. в списке доверенных нет нужного корневого сертификата.
thanks 1 пользователь поблагодарил Евгений Афанасьев за этот пост.
evgen.p оставлено 17.10.2019(UTC)
Offline evgen.p  
#6 Оставлено : 17 октября 2019 г. 12:09:25(UTC)
evgen.p

Статус: Участник

Группы: Участники
Зарегистрирован: 14.10.2019(UTC)
Сообщений: 13
Российская Федерация
Откуда: Екатеринбург

Сказал(а) «Спасибо»: 7 раз
Автор: Андрей Солдатов Перейти к цитате
Автор: evgen.p Перейти к цитате

Смотрю указанный Вами пример, в нём используется класс TLSContext. В приложении я не смог найти примеров его использования, и в проект он не импортится.
Может это быть из-за того, что у нас используется версия не android-csp-5.0.40424, а android-csp-5.0.40350? Можете скинуть ссылку на документацию, где этот класс описан, или пример в коде?


В любом случае - используйте последнюю сертифицированную сборку Android CSP.
Класс TLSContext есть в библиотеке cpSSL-android.

Для односторонней аутентификации необходимо в указанном мною примере необходимо передать в trustStore цепочку сертификатов веб-сервера.


Действительно, поставил новую версию, класс TLSContext нашёлся. Но как его использовать - можете подсказать? Какие переменные за что отвечают? Названия var<n> не сильно информативны... http://joxi.ru/bmo86Z4H3K1782 Уже разобрался.

UPD: хранилище необходимо создавать в коде, а не подгружать его из файловой системы.

Дополнительная просьба, можете ли Вы как-нибудь передать необходимые сертификаты для доступа к серверу, который указан в примере? (https://www.cryptopro.ru/certsrv/certcarc.asp)

Отредактировано пользователем 17 октября 2019 г. 14:23:52(UTC)  | Причина: Не указана

Offline Андрей Солдатов  
#7 Оставлено : 17 октября 2019 г. 14:17:31(UTC)
Андрей Солдатов

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 12.03.2019(UTC)
Сообщений: 326
Мужчина
Российская Федерация
Откуда: Москва

Сказал «Спасибо»: 5 раз
Поблагодарили: 69 раз в 65 постах
Автор: evgen.p Перейти к цитате

Дополнительная просьба, можете ли Вы как-нибудь передать необходимые сертификаты для доступа к серверу, который указан в примере? (https://www.cryptopro.ru/certsrv/certcarc.asp)


Используйте вот этот сертификат.
Техническую поддержку оказываем тут.
Наша база знаний.
thanks 1 пользователь поблагодарил Андрей Солдатов за этот пост.
evgen.p оставлено 17.10.2019(UTC)
Offline Евгений Афанасьев  
#8 Оставлено : 17 октября 2019 г. 15:02:16(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 3,906
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 684 раз в 645 постах
Автор: evgen.p Перейти к цитате

Какие переменные за что отвечают?

Код:

    /**
     * Функция инициализации SSLContext и создания объекта
     * SSLSocketFactory для TLS-клиента.
     *
     * TLS провайдер по умолчанию: {@link ru.CryptoPro.ssl.Provider#PROVIDER_NAME}.
     * TLS протокол по умолчанию: {@link ru.CryptoPro.ssl.Provider#ALGORITHM}.
     * Формат хранилища по умолчанию: {@link ru.CryptoPro.JCP.JCP#CERT_STORE_NAME}.
     *
     * @param trustStoreType Тип хранилища доверенных сертификатов.
     * Может быть null.
     * @param trustStorePath Путь к хранилищу доверенных сертификатов.
     * @param trustStorePassword Пароль на хранилище сертификатов.
     * @param trustManagers Менеджеры хранилища доверенных сертификатов.
     * Для получения одного менеджера должен быть передан массив по крайней
     * мере из одного элемента. Может быть null.
     *
     * @return объект SSLSocketFactory.
     * @throws Exception
     */
    public static SSLSocketFactory initClientSSL(String trustStoreType,
        String trustStorePath, String trustStorePassword, TrustManager[]
        trustManagers) throws Exception;

    /**
     * Функция инициализации SSLContext и создания объекта
     * SSLSocketFactory для TLS-клиента.
     *
     * TLS провайдер по умолчанию: {@link ru.CryptoPro.ssl.Provider#PROVIDER_NAME}.
     * TLS протокол по умолчанию: {@link ru.CryptoPro.ssl.Provider#ALGORITHM}.
     * Формат хранилища по умолчанию: {@link ru.CryptoPro.JCP.JCP#CERT_STORE_NAME}.
     *
     * @param tlsProvider TLS провайдер. Может быть null.
     * @param tlsProtocol Протокол TLS соединения. Может быть null.
     * @param trustStoreProvider Провайдер хранилища доверенных сертификатов.
     * @param trustStoreType Тип хранилища доверенных сертификатов.
     * Может быть null.
     * @param trustStorePath Путь к хранилищу доверенных сертификатов.
     * @param trustStorePassword Пароль на хранилище сертификатов.
     * @param trustManagers Менеджеры хранилища доверенных сертификатов.
     * Для получения одного менеджера должен быть передан массив по крайней
     * мере из одного элемента. Может быть null.
     *
     * @return объект SSLSocketFactory.
     * @throws Exception
     */
    public static SSLSocketFactory initClientSSL(String tlsProvider,
        String tlsProtocol, String trustStoreProvider, String trustStoreType,
        String trustStorePath, String trustStorePassword, TrustManager[]
        trustManagers) throws Exception;



thanks 1 пользователь поблагодарил Евгений Афанасьев за этот пост.
evgen.p оставлено 17.10.2019(UTC)
Offline evgen.p  
#9 Оставлено : 17 октября 2019 г. 15:50:35(UTC)
evgen.p

Статус: Участник

Группы: Участники
Зарегистрирован: 14.10.2019(UTC)
Сообщений: 13
Российская Федерация
Откуда: Екатеринбург

Сказал(а) «Спасибо»: 7 раз
Автор: Евгений Афанасьев Перейти к цитате
Помимо CSPConfig.init, надо вызвать еще несколько функций


При инициализации выполнил методы initCSPProviders(Context context) и private void initJavaProviders(). Скопировал 1-к-1, только убрал инициализацию CAdES и XAdES. В качестве пути для хранилища ключей указал
Код:
String trustStorePath = context.getFilesDir() + File.separator + BKSTrustStore.STORAGE_FILE_TRUST;


Создаю это самое хранилище, добавляю туда сертификат, который скинул Андрей. Вот код:
Код:
String trustStorePath = context.getFilesDir() + File.separator + BKSTrustStore.STORAGE_FILE_TRUST;
String trustStorePassword = String.valueOf(BKSTrustStore.STORAGE_PASSWORD);

// Сохраняем серт
KeyStore appKeyStore = KeyStore.getInstance("CertStore");
File appKeyStoreFile = new File(trustStorePath);
if (!appKeyStoreFile.exists()) {
    Log.i("Key store " + appKeyStoreFile.getName() + " not found. Creating...");
    appKeyStore.load(null);
} else {
    Log.i("Key store " + appKeyStoreFile.getName() + " found");
    FileInputStream appKeyStoreInputStream = new FileInputStream(appKeyStoreFile);
    appKeyStore.load(appKeyStoreInputStream, trustStorePassword.toCharArray());
}

CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Certificate cert = certificateFactory.generateCertificate(new ByteArrayInputStream(hexStringToByteArray(getTotSamiySert())));
appKeyStore.setCertificateEntry("cert", cert);

// Сохраняем (перезаписываем) хранилище ключей во внутреннее хранилище приложения
FileOutputStream appKeyStoreOutputStream = new FileOutputStream(appKeyStoreFile, false);
appKeyStore.store(appKeyStoreOutputStream, trustStorePassword.toCharArray());

// Из примера
String urlPath = "https://www.cryptopro.ru/certsrv/certcarc.asp";

System.setProperty("com.sun.security.enableCRLDP", "true");
System.setProperty("com.ibm.security.enableCRLDP", "true");

SSLSocketFactory factory = TLSContext.initClientSSL(null, trustStorePath, trustStorePassword, null);

connect(factory, urlPath);


При сохранении хранилища на 22й строке возвращается ошибка
Цитата:
java.security.NoSuchAlgorithmException: Unsupported operation.

Подскажите, пожалуйста, из-за чего?
Offline Евгений Афанасьев  
#10 Оставлено : 17 октября 2019 г. 16:32:27(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 3,906
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 684 раз в 645 постах
KeyStore appKeyStore = KeyStore.getInstance("CertStore");
Если используется CertStore, то укажите имя провайдера - JCP.PROVIDER_NAME:
KeyStore appKeyStore = KeyStore.getInstance("CertStore", JCP.PROVIDER_NAME);

Скорее всего, взялась реализация из JCSP, а она неполная, писать в нее нельзя. CertStore, в который можно писать, реализует JCP, если он не был добавлен с помощью Security.addProvider(new JCP()), то добавьте в коде.
Или используйте что-нибудь другое, например, BKS от Bouncycastle:
KeyStore appKeyStore = KeyStore.getInstance("BKS", BouncyCastleProvider.PROVIDER_NAME);

Отредактировано пользователем 17 октября 2019 г. 16:33:36(UTC)  | Причина: Не указана

thanks 1 пользователь поблагодарил Евгений Афанасьев за этот пост.
evgen.p оставлено 18.10.2019(UTC)
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
2 Страницы12>
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.