Working SSL infrastructure:
We have a working client/server setup where phones with the Android versions 4.2 and 4.4 act as clients that have to verify a server by its self-signed SSL certificate.
The problem:
The server certificate verification works as long as the devices have had internet access at least once before attempting to connect. However, if a factory reset is performed and the devices directly connect to a private network without internet connection the certificate verification fails.
To reproduce the behavior:
Technically, the devices should not need internet access to verify the self signed certificate. Could there be some kind of a blacklist that has to be loaded once before any SSL server verification can take place? And can I prevent this behavior?
Creating the SSL context:
//Using a client certificate
String password = "clientpass";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream is = context.getResources().openRawResource(R.raw.client);
keyStore.load(is, password.toCharArray());
is.close();
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, password.toCharArray());
KeyManager[] keyManagers = kmf.getKeyManagers();
// Using self signed certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
is = context.getResources().openRawResource(R.raw.cacert);
InputStream caInput = new BufferedInputStream(is);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
Log.i("CA","ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
// Create an SSLContext that uses our Trustmanager and Keymanager
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(keyManagers, trustManagers, null);
//create a socket to connect with the server
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) socketFactory.createSocket(serverAddr, port);
socket.setUseClientMode(true);
socket.addHandshakeCompletedListener(this);
socket.startHandshake();
Fails with the exception in startHandshake:
javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: null
Make sure the time on the device is correct, certificates have a validity period and won't validate if the date is set to the past (usually Jan 1st, 2000 after a factory reset) or future. The device will automatically sync via NTP, but that obviously doesn't work when there is no usable Internet connection.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With