Android Https запрос с использованием Volley и проблема с самозаверяющим сертификатом [решено]
У меня есть экспресс-сервер NodeJS, и я хочу отправить ему запрос Https через устройство Android.
В настоящее время мне удается просматривать веб-сайт Https через Chrome.
Это мой код Node JS:
const https = require('https');
const fs = require('fs');
const credentials = {
key: fs.readFileSync(__dirname + '/ssl/domain.key', 'utf8'),
cert: fs.readFileSync(__dirname + '/ssl/domain.crt', 'utf8')
};
let port = '443';
const server = https.createServer(credentials, app);
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
...
app.get("/connect", function(req, res){
...
});
На стороне Android я попробовал эти решения:
https://newfivefour.com/android-trust-all-ssl-certificates.html
/questions/15426909/android-volley-self-podpisannyij-sertifikat/15426918#15426918
/questions/2667333/svyaz-cherez-veb-servis-android-https-ssl-tls-12/2667355#2667355
Но я продолжаю получать эту ошибку:
com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: Connection closed by peer with params [...]
at com.android.volley.Request.deliverError(Request.java:617)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:104)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Я попытался использовать сервер TLS вместо:
const tls = require('tls'); // instead https
Но я получил ту же ошибку... Я новичок в мире Https, поэтому я думаю, что это проблема конфигурации мисс...
Как я могу решить эту проблему?
Благодарю.
Решение
Я использовал этот код:
fun newSSLSocketFactory(context: Context): SSLSocketFactory {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
val caInput: InputStream = context.resources.openRawResource(R.raw.domain)
val ca: X509Certificate = caInput.use {
cf.generateCertificate(it) as X509Certificate
}
// Create a KeyStore containing our trusted CAs
val keyStoreType = KeyStore.getDefaultType()
val keyStore = KeyStore.getInstance(keyStoreType).apply {
load(null, null)
setCertificateEntry("ca", ca)
}
// Create a TrustManager that trusts the CAs inputStream our KeyStore
val tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()
val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm).apply {
init(keyStore)
}
// Create an SSLContext that uses our TrustManager
val sslContext: SSLContext = SSLContext.getInstance("TLS").apply {
init(null, tmf.trustManagers, null)
}
val defValidator = HttpsURLConnection.getDefaultHostnameVerifier()
HttpsURLConnection.setDefaultHostnameVerifier { hostname, session ->
if (hostname == BuildConfig.SERVER_IP) {
true
} else {
defValidator.verify(hostname, session)
}
}
// Tell the URLConnection to use a SocketFactory from our SSLContext
return sslContext.socketFactory
}
и залпом:
Volley.newRequestQueue(context, HurlStack(null, NetworkHelper.newSSLSocketFactory(context)))