У меня возникли проблемы с приложением при регистрации на Android 9.
Приложение работает следующим образом: пользователь вводит свой номер телефона, затем он получает OTP, который будет используется сервером для создания сертификата с CSR, отправленным приложением. Затем сертификат приходит в ответ службы подписи сертификата.
Затем этот сертификат будет использоваться вместе с доверенным сертификатом, включенным в приложение, для связи с серверами
Проблема заключается в том, что это работает на Android 7 и 8, но в Android 9 сертификат клиента явно не подключен, поскольку, когда приложение пытается аутентифицировать, сервер отвечает сообщением об ошибке «Сертификат клиента не предоставлен».
Это это код, который я использую для генерации sslcontext:
public void initializeContext() {
final String[] PROTOCOLS = new String[]{"TLSv1.2"};
final String[] CIPHERS = {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"};
// get user password and file input stream
KeyStore keyStore = KeyStoreGestor.getKeyStore(mContext);
Certificate cert = null;
try {
if (keyStore != null) {
cert = keyStore.getCertificate(Constants.ALIAS_CERTIFICATE); //here's where we load the certificate that comes from the server.
}
} catch (KeyStoreException e) {
e.printStackTrace();
}
if (rootTrustManager == null) {
rootTrustManager = loadRootTrustManager(mContext);
}
SSLContext sslcontext = null;
KeyManagerFactory kmf = null;
try {
sslcontext = SSLContext.getInstance("TLSv1.2");
kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm()
);
if (cert == null) {
sslcontext.init(null, new TrustManager[]{rootTrustManager}, null);
} else {
isLoggedIn = true;
String password = SharedPreferencesGestor.getKeystorePassword(UnipagosApplication.getMainApplication());
kmf.init(keyStore, password.toCharArray());
sslcontext.init(kmf.getKeyManagers(), new TrustManager[]{rootTrustManager}, null);
}
} catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyManagementException | KeyStoreException e) {
e.printStackTrace();
}
// Allow TLSv1 protocol only
sslsf = new SSLConnectionSocketFactory(
sslcontext,
PROTOCOLS,
CIPHERS,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
if (httpclient != null) {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
}
Вот где я загружаю доверенный менеджер
private X509TrustManager loadRootTrustManager(Context context) {
TrustManagerFactory managerFactory = null;
X509TrustManager tm = null;
try {
managerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
managerFactory.init(KeyStoreGestor.loadTrustedKeystore(context));
TrustManager[] managers = managerFactory.getTrustManagers();
for (TrustManager tm1 : managers) {
if (tm1 instanceof X509TrustManager) {
tm = (X509TrustManager) tm1;
break;
}
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return tm;
}
И вот где я сохраняю сертификат, который приходит с сервера, который, Между прочим, в SignCertificate jsonResponse указывается как строка:
public static synchronized void storeKeyandCertX509(Context context, PrivateKey privateKey, String certificateString) {
InputStream certificateInputStream = null;
FileOutputStream keyStoreOutputStream = null;
try {
byte[] certificateBytes = Base64.decode(Base64.decode(certificateString, Base64.DEFAULT), Base64.DEFAULT);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
certificateInputStream = new ByteArrayInputStream(certificateBytes);
X509Certificate certificateX509 = (X509Certificate)certificateFactory.generateCertificate(certificateInputStream);
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(256);
keyStore = KeyStore.getInstance(KeyStore.getDefaultType(), keyPairGenerator.getProvider());
keyStore.load(null,null);
String passwordString = SharedPreferencesGestor.getKeystorePassword(context);
X509Certificate[] certChain = new X509Certificate[1];
certChain[0] = certificateX509;
keyStore.setKeyEntry(Constants.ALIAS_PRIVATE_KEY, privateKey, passwordString.toCharArray(), certChain);
keyStore.setCertificateEntry(Constants.ALIAS_CERTIFICATE, certificateX509);
keyStoreOutputStream = context.openFileOutput(Constants.KEY_STORE_FILE_NAME, Context.MODE_PRIVATE);
keyStore.store(keyStoreOutputStream, passwordString.toCharArray());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {if (certificateInputStream != null) {certificateInputStream.close();}} catch (IOException e) {e.printStackTrace();}
try {if (keyStoreOutputStream != null) {keyStoreOutputStream.close();}} catch (IOException e) {e.printStackTrace();}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
OpenSSL.sharedInstance().initializeContext();
}
}