Статус: Новичок
Группы: Участники
Зарегистрирован: 24.08.2021(UTC) Сообщений: 2
|
Добрый день! Имеется следующая реализация модуля крипто про для работы с TLS туннелем на андроиде. // CryptoproTlsModule.java
Код:package ru.tele2.appseller;
import android.content.Context;
import android.util.Log;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import ru.tele2.appseller.service.ProxyService;
import ru.tele2.appseller.service.TLSConnectionService;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import ru.CryptoPro.JCP.JCP;
import ru.CryptoPro.JCSP.CSPConfig;
import ru.CryptoPro.JCSP.JCSP;
import ru.CryptoPro.JCSP.support.BKSTrustStore;
import ru.CryptoPro.reprov.RevCheck;
import ru.CryptoPro.ssl.Provider;
import ru.CryptoPro.ssl.util.cpSSLConfig;
//import java.security.Provider;
//import ru.CryptoPro.ssl.android.Provider;
//import com.reactlibrary.service.CryptoProService;
//import com.reactlibrary.service.SSLContextService;
//import static com.reactlibrary.service.CryptoProService.SCP_ALREADY_INIT;
public class CryptoproTlsModule extends ReactContextBaseJavaModule {
private static final String TRUE = "true";
private static final String FALSE = "false";
private static final int LOCAL_PORT = 5000;
//private CryptoProService cryptoProService;
private TLSConnectionService tlsConnectionService;
private ProxyService proxyService;
private final String trustStorePath;
private static final String TRUST_STORE_TYPE = "BKS";
//private KeyStore trustStore;
private static final String PROVIDER_NAME = "BC";
private static final String[] cacerts = {"c01", "c02", "c03", "c04", "c05", "c06"};
private final char[] trustStorePass;
private final ReactApplicationContext reactContext;
public CryptoproTlsModule(ReactApplicationContext reactContext) {
super(reactContext);
this.trustStorePass = "pass".toCharArray();
this.reactContext = reactContext;
this.trustStorePath = getTrustStorePath(reactContext.getApplicationContext().getFilesDir().getAbsolutePath());
/*
try {
this.trustStore = getTrustStore(reactContext.getApplicationContext());
} catch (Exception e) {
this.trustStore = null;
}
*/
//this.trustStore = getTrustStore(reactContext.getApplicationContext());
}
@Override
public String getName() {
return "CryptoproTls";
}
@ReactMethod
public void init(Promise promise) {
String trustStorePass = "";
/*
cryptoProService = new CryptoProService(
reactContext.getApplicationContext().getFilesDir().getAbsolutePath(),
trustStorePass);
int initCode = cryptoProService.initProviders(reactContext.getApplicationContext());
*/
//JCSP myjcsp = new JCSP();
int initCode = CSPConfig.init(reactContext.getApplicationContext());
if (initCode != CSPConfig.CSP_INIT_OK && initCode != 9999) {
Log.d("CryptoPro init code", "init code" + initCode);
//callback.invoke("Error occurred during CSP initiation: " + initCode);
switch (initCode) {
// Не передан контекст приложения (null). Он необходим,
// чтобы произвести копирование ресурсов CSP, создание
// папок, смену директории CSP и т.п.
case CSPConfig.CSP_INIT_CONTEXT:
promise.reject("INIT_ERROR","Couldn't initialize context.");
break;
/**
* Не удается создать инфраструктуру CSP (папки): нет
* прав (нарушен контроль целостности) или ошибки.
* Подробности в logcat.
*/
case CSPConfig.CSP_INIT_CREATE_INFRASTRUCTURE:
promise.reject("INIT_ERROR","Couldn't create CSP infrastructure.");
break;
/**
* Не удается скопировать все или часть ресурсов CSP -
* конфигурацию, лицензию (папки): нет прав (нарушен
* контроль целостности) или ошибки.
* Подробности в logcat.
*/
case CSPConfig.CSP_INIT_COPY_RESOURCES:
promise.reject("INIT_ERROR","Couldn't copy CSP resources.");
break;
/**
* Не удается задать рабочую директорию для загрузки
* CSP. Подробности в logcat.
*/
case CSPConfig.CSP_INIT_CHANGE_WORK_DIR:
promise.reject("INIT_ERROR","Couldn't change CSP working directory.");
break;
/**
* Неправильная лицензия.
*/
case CSPConfig.CSP_INIT_INVALID_LICENSE:
promise.reject("INIT_ERROR","Invalid CSP serial number.");
break;
/**
* Не удается создать хранилище доверенных сертификатов
* для CAdES API.
*/
case CSPConfig.CSP_TRUST_STORE_FAILED:
promise.reject("INIT_ERROR","Couldn't create trust store for CAdES API.");
break;
} // switch
}
// %%% Инициализация остальных провайдеров %%%
//
// 2. Загрузка Java CSP (хеш, подпись, шифрование,
// генерация контейнеров).
//
if (Security.getProvider(JCSP.PROVIDER_NAME) == null) {
Security.addProvider(new JCSP());
} // if
//
// 3. Загрузка Java TLS (TLS).
//
// Необходимо переопределить свойства, чтобы
// использовались менеджеры из cpSSL, а не
// Harmony.
//
// Внимание!
// Чтобы не мешать не-ГОСТовой реализации, ряд свойств внизу *.ssl не
// следует переопределять. При этом не исключены проблемы в работе с
// ГОСТом там, где TLS-реализация клиента обращается к дефолтным алгоритмам
// реализаций этих factory (особенно: apache http client или HttpsURLConnection
// без SSLSocketFactory и с System.setProperty(javax.net.*)).
//
// Если инициализировать провайдер в CSPConfig с помощью initEx(), то
// свойства будут включены там, поэтому выше используется упрощенная
// версия инициализации.
//
// Security.setProperty("ssl.KeyManagerFactory.algorithm", ru.CryptoPro.ssl.Provider.KEYMANGER_ALG);
// Security.setProperty("ssl.TrustManagerFactory.algorithm", ru.CryptoPro.ssl.Provider.KEYMANGER_ALG);
//
// Security.setProperty("ssl.SocketFactory.provider", "ru.CryptoPro.ssl.SSLSocketFactoryImpl");
// Security.setProperty("ssl.ServerSocketFactory.provider", "ru.CryptoPro.ssl.SSLServerSocketFactoryImpl");
//
if (Security.getProvider(ru.CryptoPro.ssl.Provider.PROVIDER_NAME) == null) {
Security.addProvider(new ru.CryptoPro.ssl.Provider());
} // if
//
// 4. Провайдер хеширования, подписи, шифрования
// по умолчанию.
//
cpSSLConfig.setDefaultSSLProvider(JCSP.PROVIDER_NAME);
//
// 5. Загрузка Revocation Provider (CRL, OCSP).
//
if (Security.getProvider(RevCheck.PROVIDER_NAME) == null) {
Security.addProvider(new RevCheck());
} // if
//
// 6. Отключаем проверку цепочки штампа времени (CAdES-T),
// чтобы не требовать него CRL.
//
System.setProperty("ru.CryptoPro.CAdES.validate_tsp", "false");
//
// 7. Таймауты для CRL на всякий случай.
//
System.setProperty("com.sun.security.crl.timeout", "5");
System.setProperty("ru.CryptoPro.crl.read_timeout", "5");
// 8. Включаем возможность онлайновой проверки
// статуса сертификата.
//
// Для TLS проверку цепочки сертификатов другой стороны
// можно отключить, если создать параметр
// Enable_revocation_default=false в файле android_pref_store
// (shared preferences), см.
// {@link ru.CryptoPro.JCP.tools.pref_store#AndroidPrefStore}.
System.setProperty("com.sun.security.enableCRLDP", "true");
System.setProperty("com.ibm.security.enableCRLDP", "true");
// 9. Дополнительно задаем путь к хранилищу доверенных
// сертификатов.
// Не обязательно, если нет кода, использующего такой
// способ получения списка доверенных сертификатов.
//
// Внимание!
// Чтобы не мешать не-ГОСТовой реализации, ряд свойств внизу *.ssl и
// javax.net.* НЕ следует переопределять. Но при этом не исключены проблемы
// в работе с ГОСТом там, где TLS-реализация клиента обращается к дефолтным
// алгоритмам реализаций этих factory (особенно: apache http client или
// HttpsURLConnection без передачи SSLSocketFactory).
// Здесь эти свойства НЕ включены, т.к. нет примеров работы с УЦ 1.5,
// использующих алгоритмы по умолчанию.
//
// final String trustStorePath = getLocalTrustStorePath();
// final String trustStorePassword = String.valueOf(getLocalTrustStorePassword());
//
// Log.d(Constants.APP_LOGGER_TAG, "Default trust store: " + trustStorePath);
//
// System.setProperty("javax.net.ssl.trustStoreType", getLocalTrustStoreType());
// System.setProperty("javax.net.ssl.trustStore", trustStorePath);
// System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
// Disable required certificate and host checking
System.setProperty("tls_prohibit_disabled_validation", "false");
System.setProperty("javax.net.ssl.trustStoreType", TRUST_STORE_TYPE);
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", String.valueOf(trustStorePass));
Security.addProvider(new BouncyCastleProvider());
promise.resolve(null);
}
private String getTrustStorePath(String trustStoreRoot) {
return new StringBuilder()
.append(trustStoreRoot)
.append(File.separator)
.append(BKSTrustStore.STORAGE_DIRECTORY)
.append(File.separator)
.append(BKSTrustStore.STORAGE_FILE_TRUST)
.toString();
}
@ReactMethod
public void startProxy(String host, int port, Promise promise) {
//if (cryptoProService != null && cryptoProService.isContextInitialized()) {
Log.d("CryptoPro","Trying to start proxy");
try {
/*
SSLContextService sslContextService = new SSLContextService(
cryptoProService.getTrustStore(reactContext)
);
*/
tlsConnectionService =
new TLSConnectionService(createSSLContext());
proxyService = new ProxyService(LOCAL_PORT, host, port, tlsConnectionService);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
proxyService.startProxy();
} catch (Exception e) {
Log.e("Cryptopro", e.getMessage(), e);
}
}
});
thread.start();
//thread.join();
//proxyService.startProxy();
promise.resolve(null);
Log.d("CryptoPro","start proxy success");
} catch (Exception e) {
Log.e("Cryptopro", e.toString());
promise.reject("START_PROXY_ERROR",e.toString());
Log.d("CryptoPro","start proxy fail");
}
}
private SSLContext createSSLContext() throws Exception {
Log.i("CryptoPro", "Creating SSL context...");
/*
KeyStore keyStore = KeyStore.getInstance("HDImageStore", "JCP");
keyStore.load(null, null);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("GostX509");
kmf.init(keyStore, "1".toCharArray()); // пароль для подбора контейнера
KeyStore trustedKeyStore = KeyStore.getInstance("JKS");
//KeyStore trustedKeyStore = KeyStore.getInstance(JCP.CERT_STORE_NAME);
trustedKeyStore.load(new FileInputStream("store.jks"), "123456".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("GostX509");
tmf.init(trustedKeyStore);
SSLContext sslContext = SSLContext.getInstance("GostTLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
*/
KeyStore trustStore = getTrustStore(reactContext.getApplicationContext());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("GostX509");
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("GostTLS");
sslContext.init(null, tmf.getTrustManagers(), null);
/*
SSLContext sslContext = TLSContext.initClientSSL(
Provider.PROVIDER_NAME, // провайдер, по умолчанию - JTLS
null, // протокол, по умолчанию - GostTLS
BouncyCastleProvider.PROVIDER_NAME,
BKSTrustStore.STORAGE_TYPE,
trustStorePath,
String.valueOf(""),
null
);
*/
Log.i("CryptoPro", "SSL context created successfully!");
return sslContext;
}
private KeyStore getTrustStore(Context appContext) throws Exception {
Log.d("CryptoPro", "truststore start");
KeyStore trustStore = KeyStore.getInstance(JCP.CERT_STORE_NAME);
trustStore.load(null, trustStorePass);
//installCacerts(appContext, trustStore);
if (!isCertsInstalled(cacerts, Collections.list(trustStore.aliases()))) {
Log.d("CryptoPro", "Installing certs");
installCacerts(appContext, trustStore);
}
return trustStore;
}
private void installCacerts(Context appContext, KeyStore trustStore) throws IOException, CertificateException, KeyStoreException {
Log.d("Cryptopro","installCacerts start");
for (String certName : cacerts) {
InputStream ins = appContext.getResources().openRawResource(
appContext.getResources().getIdentifier(certName,
"raw", appContext.getPackageName()));
byte[] certData = new byte[ins.available()];
ins.read(certData);
InputStream bais = new ByteArrayInputStream(certData);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Certificate certificate = certificateFactory.generateCertificate(bais);
trustStore.setCertificateEntry(certName, certificate);
}
}
private boolean isCertsInstalled(String[] certNames, List<String> trustStoreAliases) {
boolean result = true;
for (String name : certNames) {
if (!trustStoreAliases.contains(name)) {
result = false;
break;
}
}
return result;
}
}
На андроиде 10 и ниже версии все при отправке запроса на сервер все работает корректно, но на андроиде 11+ возникают ошибки вида: javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty W/JCP: ru.CryptoPro.ssl.pc_4.cl_4.<clinit> :: X.509 not found java.security.cert.CertificateException: X.509 not found (эта возникает так же и на 10 андроиде, но при этом все работает) Подскажите, пожалуйста, как решить эту проблему? Отредактировано пользователем 12 января 2022 г. 11:27:05(UTC)
| Причина: Не указана
|