Статус: Участник
Группы: Участники
Зарегистрирован: 14.10.2019(UTC) Сообщений: 13 Откуда: Екатеринбург Сказал(а) «Спасибо»: 7 раз
|
Разрабатываю плагин на Кордову для возможности отправки запросов с клиента по TLS с ГОСТовскими сертификатами, односторонняя аутентификация. Для тестов использую https://cpca.cryptopro.ru/default.htm, также через curl получил сертификат для этого сайта. Задача: используя полученный сертификат достучаться до сервера и получить от него ответ. Мои действия: - Проинициализировал провайдер
Код:CSPConfig.initEx(context)
- Создал контейнер
Код: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
- Создал объект сертификата
Код:CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream certInputStream = new ByteArrayInputStream(getSert().getBytes());
Certificate certificate = certificateFactory.generateCertificate(certInputStream);
Метод getSert() возвращает сертификат в текстовом виде. Вот он:
-----BEGIN CERTIFICATE----- MIIFszCCBR+gAwIBAgIRASPbswAqquWUTTN7vnpPu0wwCgYIKoUDBwEBAwMwgbcx IDAeBgkqhkiG9w0BCQEWEWNwY2FAY3J5cHRvcHJvLnJ1MQswCQYDVQQGEwJSVTEV MBMGA1UECAwM0JzQvtGB0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAxJTAj BgNVBAoMHNCe0J7QniAi0JrQoNCY0J/QotCeLdCf0KDQniIxMTAvBgNVBAMMKNCj 0KYg0JrQoNCY0J/QotCeLdCf0KDQniAo0JPQntCh0KIgMjAxMikwHhcNMTkwNDA5 MTA0NDUwWhcNMjAwNzA5MTA1NDUwWjCBgDELMAkGA1UEBhMCUlUxFTATBgNVBAgM DNCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMSUwIwYDVQQKDBzQ ntCe0J4gItCa0KDQmNCf0KLQni3Qn9Cg0J4iMRwwGgYDVQQDDBPQktC10LEt0YHQ tdGA0LLQtdGAMGYwHwYIKoUDBwEBAQEwEwYHKoUDAgIkAAYIKoUDBwEBAgIDQwAE QIITMP2Iim2Leke0e2wwFWzAEQ0xfDkd0pi2rRmeTUWvBG3wPKHk1ET+Xrsa8jVj hiiE9EuUmsGGMy5GSOJOU32jggMyMIIDLjAOBgNVHQ8BAf8EBAMCBDAwHQYDVR0O BBYEFG8xcETJuDMQ9YdSiHUKpH/+rYUPMB8GCSsGAQQBgjcVBwQSMBAGCCqFAwIC LgAEAgEBAgEAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMBsGCSsGAQQBgjcVCgQOMAww CgYIKwYBBQUHAwEwgaEGCCsGAQUFBwEBBIGUMIGRMDYGCCsGAQUFBzABhipodHRw Oi8vb2NzcC5jcnlwdG9wcm8ucnUvb2NzcDIwMTIvb2NzcC5zcmYwVwYIKwYBBQUH MAKGS2h0dHA6Ly9jcGNhMjAuY3J5cHRvcHJvLnJ1L2FpYS9mZGY1NTI2OGFiNmI0 OGFhN2VmYjY5NWY3MjJhN2ExNzA5YjA5YTM3LmNydDAxBgNVHREEKjAoghFjcGNh LmNyeXB0b3Byby5ydYITY3BjYTIwLmNyeXB0b3Byby5ydTArBgNVHRAEJDAigA8y MDE5MDQwOTEwNDQ1MFqBDzIwMjAwNDA5MTA0NDUwWjCBrgYDVR0fBIGmMIGjME6g TKBKhkhodHRwOi8vY2RwLmNyeXB0b3Byby5ydS9jZHAvZmRmNTUyNjhhYjZiNDhh YTdlZmI2OTVmNzIyYTdhMTcwOWIwOWEzNy5jcmwwUaBPoE2GS2h0dHA6Ly9jcGNh MjAuY3J5cHRvcHJvLnJ1L2NkcC9mZGY1NTI2OGFiNmI0OGFhN2VmYjY5NWY3MjJh N2ExNzA5YjA5YTM3LmNybDCB9AYDVR0jBIHsMIHpgBT99VJoq2tIqn77aV9yKnoX CbCaN6GBvaSBujCBtzEgMB4GCSqGSIb3DQEJARYRY3BjYUBjcnlwdG9wcm8ucnUx CzAJBgNVBAYTAlJVMRUwEwYDVQQIDAzQnNC+0YHQutCy0LAxFTATBgNVBAcMDNCc 0L7RgdC60LLQsDElMCMGA1UECgwc0J7QntCeICLQmtCg0JjQn9Ci0J4t0J/QoNCe IjExMC8GA1UEAwwo0KPQpiDQmtCg0JjQn9Ci0J4t0J/QoNCeICjQk9Ce0KHQoiAy MDEyKYIRAeP79gAxqVeVQMpBRdsMF5wwCgYIKoUDBwEBAwMDgYEAXnHO0s/fPpoq nHP7adyggEmSxBZJEZwbWkoTWK0YSuJyooZ2wCDrI2Up3qLcCyASCfH6H5B9sd0c 1NIOcH/Zc7PLhraWPliz2f7bdmD5cFHKvLOoSJvQqIFcUSI3GHI3cYg2BkKSUpSb 7j2lw0jebFOBlOfB0yzRUQejYLC0q4A= -----END CERTIFICATE-----
- Загрузил сертификат в контейнер
Код:trustStore.setCertificateEntry("cpSert", certificate);
- Создаю контекст 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);
- Пытаюсь подключиться
Код: 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)
| Причина: Не указана
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 12.03.2019(UTC) Сообщений: 332 Откуда: Москва Сказал «Спасибо»: 5 раз Поблагодарили: 70 раз в 66 постах
|
Добрый день. Посмотрите samples-sources.jar -> JTLS_samples -> ClientSample из состава дистрибутива. Там есть пример односторонней аутентификации TLS клиента. |
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 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)
| Причина: Не указана
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 12.03.2019(UTC) Сообщений: 332 Откуда: Москва Сказал «Спасибо»: 5 раз Поблагодарили: 70 раз в 66 постах
|
Автор: evgen.p Смотрю указанный Вами пример, в нём используется класс TLSContext. В приложении я не смог найти примеров его использования, и в проект он не импортится. Может это быть из-за того, что у нас используется версия не android-csp-5.0.40424, а android-csp-5.0.40350? Можете скинуть ссылку на документацию, где этот класс описан, или пример в коде?
В любом случае - используйте последнюю сертифицированную сборку Android CSP. Класс TLSContext есть в библиотеке cpSSL-android. Для односторонней аутентификации необходимо в указанном мною примере необходимо передать в trustStore цепочку сертификатов веб-сервера. |
|
1 пользователь поблагодарил Андрей Солдатов за этот пост.
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 06.12.2008(UTC) Сообщений: 3,962 Откуда: Крипто-Про Сказал(а) «Спасибо»: 20 раз Поблагодарили: 704 раз в 665 постах
|
Добрый день.
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" - не удалось построить цепочку сертификатов. Предполагаю, что не строится цепочка другой стороны (сервера), т.к. в списке доверенных нет нужного корневого сертификата. |
|
1 пользователь поблагодарил Евгений Афанасьев за этот пост.
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 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)
| Причина: Не указана
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 12.03.2019(UTC) Сообщений: 332 Откуда: Москва Сказал «Спасибо»: 5 раз Поблагодарили: 70 раз в 66 постах
|
Автор: evgen.p Дополнительная просьба, можете ли Вы как-нибудь передать необходимые сертификаты для доступа к серверу, который указан в примере? (https://www.cryptopro.ru/certsrv/certcarc.asp)
Используйте вот этот сертификат. |
|
1 пользователь поблагодарил Андрей Солдатов за этот пост.
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 06.12.2008(UTC) Сообщений: 3,962 Откуда: Крипто-Про Сказал(а) «Спасибо»: 20 раз Поблагодарили: 704 раз в 665 постах
|
Автор: 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;
|
|
1 пользователь поблагодарил Евгений Афанасьев за этот пост.
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 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. Подскажите, пожалуйста, из-за чего?
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 06.12.2008(UTC) Сообщений: 3,962 Откуда: Крипто-Про Сказал(а) «Спасибо»: 20 раз Поблагодарили: 704 раз в 665 постах
|
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)
| Причина: Не указана |
|
1 пользователь поблагодарил Евгений Афанасьев за этот пост.
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close