Я знаю, что это сообщение довольно старо, bui я хочу совместно использовать решение, которое работало на меня с последним обновлением OkHttp, 3.12.1
версия во время, которое я пишу.
, В первую очередь, необходимо получить объект KeyStore, который будет затем добавлен к TrustManager:
/**
* @param context The Android context to be used for retrieving the keystore from raw resource
* @return the KeyStore read or null on error
*/
private static KeyStore readKeyStore(Context context) {
char[] password = "keystore_password".toCharArray();
// for non-android usage:
// try(FileInputStream is = new FileInputStream(keystoreName)) {
try(InputStream is = context.getResources().openRawResource(R.raw.keystore)) {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(is, password);
return ks;
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return null;
}
Теперь можно получить сборку OkHttpClient
с самоподписанным сертификатом в keystore:
/**
* @param context The Android context used to obtain the KeyStore
* @return the builded OkHttpClient or null on error
*/
public static OkHttpClient getOkHttpClient(Context context) {
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(readKeyStore(context));
X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, null);
return new OkHttpClient.Builder()
.hostnameVerifier((hostname, session) -> {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
/* Never return true without verifying the hostname, otherwise you will be vulnerable
to man in the middle attacks. */
return hv.verify("your_hostname_here", session);
})
.sslSocketFactory(sslContext.getSocketFactory(), trustManager)
.build();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Помнят, что этому высоко препятствуют для возврата всегда верный в hostnameVerifier
для предотвращения риска человека в средних нападениях.
У меня была та же проблема, и я зафиксировал ее с клиент okhttp следующим образом:
1.) Добавляют certificate
файл к src/main/res/raw/
, который включает это содержание:
-----BEGIN CERTIFICATE-----
...=
-----END CERTIFICATE-----
2.) Instanciate okHttpClient:
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(getSslContext(context).getSocketFactory())
.build();
3.) Вот используемый getSslContext(Context context)
метод:
SSLContext getSslContext(Context context) throws Exception {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); // "BKS"
ks.load(null, null);
InputStream is = context.getResources().openRawResource(R.raw.certificate);
String certificate = Converter.convertStreamToString(is);
// generate input stream for certificate factory
InputStream stream = IOUtils.toInputStream(certificate);
// CertificateFactory
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// certificate
Certificate ca;
try {
ca = cf.generateCertificate(stream);
} finally {
is.close();
}
ks.setCertificateEntry("av-ca", ca);
// TrustManagerFactory
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
// Create a TrustManager that trusts the CAs in our KeyStore
tmf.init(ks);
// Create a SSLContext with the certificate that uses tmf (TrustManager)
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
return sslContext;
}
, Если существует потребность добавить несколько сертификатов SslContext, здесь , решение.