Using a Custom Certificate Trust Store on Android
As mentioned in a previous post, Android 4.0 (ICS) adds both a system UI and SDK API's that let you add certificates to the system trust store. On all previous version though, the system trust store is read-only and there is no way to add certificates on non-rooted devices. Therefore, if you want to connect to a server that is using a certificate not signed by one of the CA's included in the system trust store (including a self-signed one), you need to create and use a private trust store for the application. That is not particularly hard to do, but 'how to connect to a server with a self-signed certificate' is one of the most asked Android questions on StackOverflow, and the usual answer goes along the lines of 'simply trust all certificates and you are done'. While this will indeed let you connect, and might be OK for testing, it defeats the whole purpose of using HTTPS: your connection might be encrypted but you have no way of knowing who you are talking to. This opens the door to man-in-the-middle (MITM) attacks, and, needless to say, is bad practice. In this post we will explore how Android's HTTPS system works pre-ICS and show how to create and use a custom certificate trust store and a dynamically configurable
Some background: JSSE
Java, and by extension Android, implement SSL using a framework called Java Secure Socket Extension (JSSE). A discussion of how SSL and JSSE work is beyond the scope of this post, but you can find a shot introduction to SSL in the context of JSSE here. In brief, SSL provides both privacy and data integrity (i.e., an encrypted communications channel) and authentication of the parties involved. Authentication is implemented using public key cryptography and certificates. Each party presents their certificate, and if the other party trusts it, they negotiate a shared key to encrypt communications using the associated key pairs (public and private). JSSE delegates trust decisions to a
One way to specify the trust anchors is to add the CA certificates to a Java key store file, referred to as a 'trust store'. The default JSSE
Android and
If you want to specify your own system trust store file in desktop Java, it is just a matter of setting a value to the
If you now use
If we can change the set of trusted certificates using this property, connecting to a server using a custom certificate should be easy, right? It turns out this is not the case. You can try it yourself using the sample app: pressing 'Default Connect' will result in a 'Trust anchor for certificate path not found' error regardless of the state of the 'Set javax.net.ssl.trustStore' checkbox. A little further investigation reveals that the default
Using your own trust store: HttpClient
Since we can't use the 'easy way' on Android, we need to specify the trust store to use programmatically. This is not hard either, but first we need to create a key store file with the certificates we need. The sample project contains a shell script that does this automatically. All you need is a recent Bouncy Castle jar file and the openssl command (usually available on Linux systems). Drop the jar and a certificate (in PEM format) in the script's directory and run it like this:
This will calculate the certificate subject's hash and use it as the alias in a Bouncy Castle key store file (BKS format) created in the application's
Apache's HttpClient provides a convenient
Once initialized like this, the
Using your own trust store: HttpsURLConnection
Another popular HTTPS API on Android is HttpsURLConnection. Despite the not particularly flexible or expressive interface, apparently this is the preferred API from Android 2.3 (Gingerbread) and on. Whether to actually use is it is, of course, entirely up to you :) It uses JSSE to connect via HTTPS, so initializing it with our own trust and/or key store involves creating and initializing an
In this example we are using both a trust store and a key store, but if you don't need client authentication, you can just pass
Creating a dynamic
As mentioned above, a
To address the second problem, we simply copy the trust store to internal storage when we first start the application and use that file to initialize our
Using our
Initializing an
You can check that this actually works with the 'HttpClient Connect' and 'HttpsURLConnection Connect' buttons of the sample application. Both clients are using our custom
Summary
We've shown how the default
TrustManager
.Some background: JSSE
Java, and by extension Android, implement SSL using a framework called Java Secure Socket Extension (JSSE). A discussion of how SSL and JSSE work is beyond the scope of this post, but you can find a shot introduction to SSL in the context of JSSE here. In brief, SSL provides both privacy and data integrity (i.e., an encrypted communications channel) and authentication of the parties involved. Authentication is implemented using public key cryptography and certificates. Each party presents their certificate, and if the other party trusts it, they negotiate a shared key to encrypt communications using the associated key pairs (public and private). JSSE delegates trust decisions to a
TrustManager
class, and authentication key selection to a KeyManager
class. Each SSLSocket
instance created via JSSE has access to those classes via the associated SSLContext
(you can find a pretty picture here). Each TrustManager
has a set of trusted CA certificates (trust anchors) and makes trust decisions based on those: if the target party's certificate is issued by one of the trusted CA's, it is considered trusted itself.One way to specify the trust anchors is to add the CA certificates to a Java key store file, referred to as a 'trust store'. The default JSSE
TrustManager
is initialized using the system trust store which is generally a single key store file, saved to a system location and pre-populated with a set of major commercial and government CA certificates. I
f you want to change this, you need to create an appropriately configured TrustManager
instance, either via a TrustManagerFactory
, or by directly implementing the X509TrustManager
interface. To make the general case where one just wants to use their own key store file to initialize the default TrustManager
and/or KeyManager
, JSSE provides a set of system properties to specify the files to use.Android and
javax.net.ssl.trustStore
If you want to specify your own system trust store file in desktop Java, it is just a matter of setting a value to the
javax.net.ssl.trustStore
system property when starting the program (usually using the -D
JVM command line parameter). This property is also supported on Android, but things work a little differently. If you print the value of the property it will most likely be /system/etc/security/cacerts.bks
, the system trust store file (pre-ICS; the property is not set on ICS). This value is used to intialize the default TrustManagerFactory
, which in turn creates an X.509 certificate-based TrustManager
. You can print the current trust anchors like this:TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init((KeyStore) null); X509TrustManager xtm = (X509TrustManager) tmf.getTrustManagers()[0]; for (X509Certificate cert : xtm.getAcceptedIssuers()) { String certStr = "S:" + cert.getSubjectDN().getName() + "\nI:" + cert.getIssuerDN().getName(); Log.d(TAG, certStr); }
If you now use
System.setProperty()
to point the property to your own trust store file, and run the above code again, you will see that it outputs the certificates in the specified file. Check the 'Set javax.net.ssl.trustStore' checkbox and use the 'Dump trusted certs' button of the sample app to try it. If we can change the set of trusted certificates using this property, connecting to a server using a custom certificate should be easy, right? It turns out this is not the case. You can try it yourself using the sample app: pressing 'Default Connect' will result in a 'Trust anchor for certificate path not found' error regardless of the state of the 'Set javax.net.ssl.trustStore' checkbox. A little further investigation reveals that the default
SSLContext
is already initialized with the system trust anchors and setting the javax.net.ssl.trustStore
property does not change this. Why? Because Android pre-loads system classes, and by the time your application starts, the default SSLContext
is already initialized. Of course, any TrustManager
's you create after setting the property will pick it up (see above).Using your own trust store: HttpClient
Since we can't use the 'easy way' on Android, we need to specify the trust store to use programmatically. This is not hard either, but first we need to create a key store file with the certificates we need. The sample project contains a shell script that does this automatically. All you need is a recent Bouncy Castle jar file and the openssl command (usually available on Linux systems). Drop the jar and a certificate (in PEM format) in the script's directory and run it like this:
$ ./importcert.sh cacert.pem
This will calculate the certificate subject's hash and use it as the alias in a Bouncy Castle key store file (BKS format) created in the application's
raw/
resource directory. The script deletes the key store file if it already exists, but you can easily modify it to append certificates instead. If you are not the command-line type, you can use the Portecle GUI utility to create the key store file. Apache's HttpClient provides a convenient
SSLSocketFactory
class that can be directly initialized with a trust store file (and a key store file if client authentication is needed). All you need to do is to register it in the scheme registry to handle the https
scheme:KeyStore localTrustStore = KeyStore.getInstance("BKS"); InputStream in = getResources().openRawResource(R.raw.mytruststore); localTrustStore.load(in, TRUSTSTORE_PASSWORD.toCharArray()); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory .getSocketFactory(), 80)); SSLSocketFactory sslSocketFactory = new SSLSocketFactory(trustStore); schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); HttpParams params = new BasicHttpParams(); ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); HttpClient client = new DefaultHttpClient(cm, params);
Once initialized like this, the
HttpClient
instance will use our local trust store when verifying server certificates. If you need to use client authentication as well, just load and pass the key store containing the client's private key and certificate to the appropriate SSLSocketFactory
constructor. See the sample project for details and use the 'HttpClient SSLSocketFactory Connect' button to test. Note that, when initialized like this, our HttpClient
will use only the certificates in the specified file, completely ignoring the system trust store. Thus connections to say, https://google.com
will fail. We will address this later. Using your own trust store: HttpsURLConnection
Another popular HTTPS API on Android is HttpsURLConnection. Despite the not particularly flexible or expressive interface, apparently this is the preferred API from Android 2.3 (Gingerbread) and on. Whether to actually use is it is, of course, entirely up to you :) It uses JSSE to connect via HTTPS, so initializing it with our own trust and/or key store involves creating and initializing an
SSLContext
(HttpClient's SSLSocketFactory
does this behind the scenes):KeyStore trustStore = loadTrustStore(); KeyStore keyStore = loadKeyStore(); TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); KeyManagerFactory kmf = KeyManagerFactory .getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, KEYSTORE_PASSWORD.toCharArray()); SSLContext sslCtx = SSLContext.getInstance("TLS"); sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); URL url = new URL("https://myserver.com"); HttpsURLConnection urlConnection = (HttpsURLConnection) url urlConnection.setSSLSocketFactory(sslCtx.getSocketFactory());
In this example we are using both a trust store and a key store, but if you don't need client authentication, you can just pass
null
as the first parameter of SSLContext.init()
. Creating a dynamic
TrustManager
As mentioned above, a
TrustManager
initialized with a custom trust store will only use the certificates in that store as trust anchors: the system defaults will be completely ignored. Sometimes this is all that is needed, but if you need to connect to both your own server and other public servers that use HTTPS (such as Twitter, for example), you will need to create two separate instances of HttpClient
or HttpsURLConnection
and switch between the two. Additionally, since the trust store is stored as an application resource, there is no way to add trusted certificates dynamically, you need to repackage the application to update the trust anchors. Certainly we can do better than that. The first problem is easily addressed by creating a custom TrustManager
that delegates certificate checks to the system default one and uses the local trust store if verification fails. Here's how this looks like:public class MyTrustManager implements X509TrustManager { private X509TrustManager defaultTrustManager; private X509TrustManager localTrustManager; private X509Certificate[] acceptedIssuers; public MyTrustManager(KeyStore localKeyStore) { // init defaultTrustManager using the system defaults // init localTrustManager using localKeyStore } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { try { defaultTrustManager.checkServerTrusted(chain, authType); } catch (CertificateException ce) { localTrustManager.checkServerTrusted(chain, authType); } } //... }
To address the second problem, we simply copy the trust store to internal storage when we first start the application and use that file to initialize our
TrustManager
's. Since the file is owned by the application, you can easily add and remove trusted certificates. To test modifying the trust store works, copy a certificate file(s) in DER format to the SD card (external storage) root and use the sample application's 'Add certs' and 'Remove certs' menus to add or remove it to/from the local trust store file. You can then verify the contents of the file by using the 'Dump trusted certs' button (don't forget to check 'Set javax.net.ssl.trustStore'). To implement this the app simply uses the JCE KeyStore
API to add or remove certificates and save the trust store file:CertificateFactory cf = CertificateFactory.getInstance("X509"); InputStream is = new BufferedInputStream(new FileInputStream(certFile)); X509Certificate cert = (X509Certificate) cf.generateCertificate(is); String alias = hashName(cert.getSubjectX500Principal()); localTrustStore.setCertificateEntry(alias, cert); FileOutputStream out = new FileOutputStream(localTrustStoreFile); localTrustStore.store(out, TRUSTSTORE_PASSWORD.toCharArray());
Using our
MyTrustManager
with HttpsURLConnection
is not much different than using the default one:MyTrustManager myTrustManager = new MyTrustManager(localTrustStore); TrustManager[] tms = new TrustManager[] { myTrustManager }; SSLContext sslCtx = SSLContext.getInstance("TLS"); context.init(null, tms, null); HttpsURLConnection urlConnection = (HttpsURLConnection) url .openConnection(); urlConnection.setSSLSocketFactory(sslCtx.getSocketFactory());
HttpClient
's SSLSocketFactory
doesn't let us specify a custom TrustManager
, so we need to create our own SocketFactory
. To make initialization consistent with that of HttpsURLConnection
, we have it take an already initialized SSLContext
as a parameter and use it to get a factory that lets us create SSL sockets as needed:public class MySSLSocketFactory implements LayeredSocketFactory { private SSLSocketFactory socketFactory; private X509HostnameVerifier hostnameVerifier; public MySSLSocketFactory(SSLContext sslCtx, X509HostnameVerifier hostnameVerifier) { this.socketFactory = sslCtx.getSocketFactory(); this.hostnameVerifier = hostnameVerifier; } //.. @Override public Socket createSocket() throws IOException { return socketFactory.createSocket(); } }
Initializing an
HttpClient
instance is now simply a matter of registering our socket factory for the https
scheme:SSLContext sslContext = createSslContext(); MySSLSocketFactory socketFactory = new MySSLSocketFactory( sslContext, new BrowserCompatHostnameVerifier()); schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
You can check that this actually works with the 'HttpClient Connect' and 'HttpsURLConnection Connect' buttons of the sample application. Both clients are using our custom
TrustManager
outlined above and trust anchors are loaded dynamically: adding and removing certificates via the menu will directly influence whether you can connect to the target server.Summary
We've shown how the default
TrustManager
on pre-ICS Android devices works and how to set up both HttpClient
and HttpsURLConnection
to use a local (application-scoped) trust and/or key store. In addition, the sample app provides a custom TrustManager
implementation that both extends the system one, and supports dynamically adding and removing application-specified trust anchors. While this is not as flexible as the system-wide trust store introduced in ICS, it should be sufficient for most applications that need to manage their own SSL trust store. Do use those examples as a starting point and please do not use any of the trust-all 'solutions' that pop up on StackOverflow every other day.
Comments
I am trying to build a authentication system that will run with my android phones.
I wrote the following in a extends AndroidUnitTestCase class
X509Certificate[] certList = xtm.getAcceptedIssuers() ;
for (X509Certificate cert : certList) {
String certStr = "S:" + cert.getSubjectDN().getName() + "\nI:"
+ cert.getIssuerDN().getName();
System.out.println(certStr+"<<"+cert.getPublicKey()+">>") ;
}
This prints out
S:C=US,O=VeriSign\, Inc.,OU=VeriSign Trust Network,OU=(c) 1999 VeriSign\, Inc. - For authorized use only,CN=VeriSign Class 4 Public << AND THE PUBLIC KEY >>
Does the above certificate always ship with Android phones and emulators ? I am hoping to always use Verisign's cert.getPublicKey to encrypt some of my data to achieve client authentication. But if Verisign does not ship with all phones and emulators, I hope to identify a minimal set of certificates that do ship (for sure). So that I can play with that.
Anmol
As for what certificates ship by default, there are no guarantees since I believe carries can customize this and add or remove certificates. That said, you can usually rely on VeriSign being there, but they have multiple CA's and multiple certificates, so newer ones might be missing from some versions of Android.
Generally, you should only care that the CA that issued your server, etc. certificate is trusted by default by Android, so that your certificate validates out of the box. If it is not, you have to use the techniques outlined in this post on pre-ICS devices. On ICS, you can simply use the system settings or the provided APIs to add trusted certificates.
My scenario is, that my server can only be contacted by my clients, which I package and release. So, can I use some basic certificate or do I need to spend that 100-200$ to get a certificate from symantec ?
Unfortunately, I have not been able to run your sample program with success.
I have an own web server with a signed certificate from COMODO CA Limited.
Using ISP Manager I downloaded a .crt (=.pem) and a .p12 (=.pfx) using a random password. Creating the mytruststore.bks using importcert.sh seems successful.
However, using any of the options triggers the error 'Not trusted server certificate'. When I dump the trusted certs I see the correct domain being found.
Any thoughts on what I could be doing wrong?
I am on Android 2.2 (API 8). I am using bcprov-jdk15on-146.jar.
Many thanks in advance!
Glad you find this post useful.
As for your problem, there might be many possible causes. For starters, how does your server certificate chain look like? With a commercial CA, it is most probably issued by an intermediate CA (which may in turn be issued by another intermediate CA). If so, does your webserver send the intermediate CA certificates? Additionally, there is a bug in how Android handles out-of-order certificates in 2.1 and 2.2, so you might be hitting this. The easiest way to check what exactly the server is sending is to use the 'openssl s_client -connect myserver.com' command.
You mention a .p12 file, are you trying to do client authentication? Finally, what is in the PEM file? If the server is sending the intermediate certificates properly (see above), all you need is the Comodo root CA certificate.
Thank you for your quick reply!
I am quite new to SSL, so I am not entirely sure I know what I am doing ;)
Using the command you suggested and adding -showcerts leaves me with three certificates (the output is a bit large to put over here). Adding all three in the truststore did not make a difference.
However, I have tried two identical phones running the same system. One connects! The other does not. And you're right, the order of the certificates is not the same. So apparently the bug caused the trouble the whole time. Is there any workaround you happen to know of?
Concerning the client authentication; this is no high priority, but it would be nice if I would get it to work.
Many thanks,
Erik
By the way, I used the second comment on http://stackoverflow.com/questions/4115101/apache-httpclient-on-android-producing-certpathvalidatorexception-issuername to solve the 'out-of-order' bug.
As I am still a bit unsatisfied with my solution, I am trying to get the client authentication working as well. Again without luck.
I tried to build my own KeyManager to check the order of the certificates and it happend to be only one. Could this be correct? I again tried using your sample app, but both methods time out after a long wait. On my ICS device a get a 'Failure in SSL library, usually a protocol error' error. Any thoughts?
On my PHP server I adjusted the .htaccess to force client authentication:
| SSLVerifyClient require
| SSLVerifyDepth 3
| SSLCACertificateFile /ca.crt
Chrome gives me the following (quite promising) error: 'Unable to make a secure connection to the server. This may be a problem with the server, or it may be requiring a client authentication certificate that you don't have.'
Thanks for your help again!
Everything works grate except for one thing
When i load up the app into my device and try it
always the 'keyStore.load(..' return exception
"stream does not represent a PKCS12 key store"
When i press the button again immediately the exception is not thrown again
and everything works.
It always happens one time when loading the app into device
I guess you are referring to the HostnameVerifier? On shared hosting you should have either a wildcard certificate or one with multiple SubjectAlternativeName (SAN) extensions, one for each supported host. The DefaultHostnameVerifier should be able to handle both cases correctly, so this is either a bug (in some older Android version) or your host is somehow misconfigured. How does the certificate look like? The HosnameVerifier is independent from (PKI) certificate validation, so setting should not affect it. Why do you thing it is being disabled?
Additionally, you might want to post on StackOverflow with related code and more details. This gives more people a chance to see it and comment.
I'am writing an Android Client which needs to access a WCF-Service.
My first thinking was, that I have to write a Custom HTTP Client class, which can handle the certificates.
I have already read your other article with the KeyChain-API.
So would like to use the existing KeyStore instead of creating a custom one.
How could I accomplish this? The KeyChain-API doesn't seem to have a methode for that.
Code:
SSLSocketFactory sf = new SSLSocketFactory(trusted); // needs a KeyStore object
Thanks in advance.
Best regards,
jens
Nice post Please where can i get the sample project for HttpClient unsing the SSLSocket you mentioned above. Am stock with "No certificate peering" in my application for more than 8weeks now. I will really appreciate your help on this thanks
Also when I try to add a cert it just crashes the app, is this only for pre 4.0 phones?
ReplyDelete
Is it possible to get WebView/WebViewClient to use a custom trust store in ICS and up?
Here's a more detailed version of my question...
I've learned quite a bit from your posts re: custom certs both pre- and post- ICS and am curious if it's possible to obtain hybrid behavior on ICS: I'd like to use a custom trust store on ICS and greater, but not have it be device-wide (i.e. it's a self-signed cert that is for use within the app, not when using another browser) So I'm trying to use information from your pre-ICS post on ICS and greater... as you might expect, I'm having some difficulty.
I've confirmed that things are working as expected when manually generating requests via HttpsURLConnection but can't see a way to tell my WebView/WebViewClient to use the custom trust store. Handling in onReceivedSslError is about the best option I've found so far but that seems to result in some page rendering issues even when I just call handler.proceed() without doing anything else. Should I get past the rendering issue, it's not clear how I can obtain the actual cert from SslError to validate it manually. So that takes us back to the question at the top of this post...
Thanks,
Phil
I appreciate your response and you've saved me some time and headache continuing to look for a solution that doesn't appear to exist publicly in the API. After seeing that SslCertificate was just an opaque wrapper, I've gone the reflection route as you suggested.
Thanks again for your help,
Phil
I am following same process at my end, All works fine for till android 4.1 & Below.
But It wont work on and 4.1 & Above.
Can you please help me this.
thank you for the only post I found in the internet that seems to solve the problem to accept and manage self-signed certificates in Android!!
Unfortunately it doesn't work for me. I used Portecle to generate the file mytruststore.bks in res\raw, which contains one self-signed certificate.
First problem: As long as the truststore does not yet exist it is copied allright to /data/data/org.../files/mytruststore.bks. But if I want to show its content with dumpTrustedCerts(), the line "tmf.init((Keystore) null);" leads to GeneralSecurityException! Moreover: If I look in my file system, I cannot find any data/data subdirectory!
Second problem: If I want to run HttpsURLConnectionConnect(), the line localTrustStore.load(in, TRUSTSTORE_PASSWORD.toCharArray()) within the function loadTrustStore() leads to the toast "Wrong version of key store" (by the way I didn't use a password for the certificate and therefore set it to "").
Do you have any idea??
Using the mechanisms of your example I could now enable my own app to accept self-signed certificates that are already saved in the local trust store.
Now I want to do exactly what you suggested in your comment from 23 February, 2012, for not yet saved certificates.
I catch the SSLHandshakeException that occurs during httpsUrlConnection.getOutputStream(). But how can I now get the server certificate? Calling httpsUrlConnection.getServerCertificates() within the catch block would make the app stopp unexpectedly :-(
Do you have any idea how to get the certificate from server?
During httpsUrlConnection.getOutputStream() there is a call to MyTrustManager.checkServerTrusted(). This function throws a CertificateException if the certificate is not found in the default trust store. But it is still available as long as it has not yet looked up in the local trust store. This is the perfect place to save the certificate in a temporary file. If the certificate is not found in the local trust store too, then httpsUrlConnection.getOutputStream() throws an SSLHandshakeException and here I can show the user the content of the temporary saved certificate to let him decide if he wants to trust it!
Thank you again for your excellent article, it helped me a lot!
With your application I realized that my connection, just like yours works with client authentication, but only if I first call that connect without client authentication. If I directly use client authentication, I get the connection reset by peer error, even with your app. Am I still missing something? Because if I try a connection with the Chrome Browser, everything works. :-/
InputStream in = getResources().openRawResource(R.raw.mytruststore);
Gets me the error:
"Cannot make a static reference to the non-static method getResources() from the type ContextWrapper"
I would like to thanks your for this nice post and github example. That's really very much helpful.
I do have one question regarding SSL HTTPS and BKS certificates usage. Suppose I create one BKS for my Host and use it in My App.
Now as you know it's easy to decompile APK and get raw folder values so anyone can obtain my BKS file.
If my web service URL is known to someone else, then is it possible for him to call the same service using this BKS file in his app or in browser ?
Please reply on this as soon as possible.
As for your question, certificates are public by definition, so extracting one from your app is not a problem. Using SSL server authentication is not a replacement for *user* authentication. If by 'BKS file' you meant 'BKS file that contains a private key', as with other credentials, you shouldn't bundle private keys with your app. Find another way to distribute them, and let uses import them into the app's store.
Thanks for detail explanation and is there anyway to convert .crt file to .bks at run time instead of reading it from res/raw folder.
Thanks
Harinadh.
Following is my code :
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(ks, KEYSTORE_PASSWORD.toCharArray());
KeyManager [] keyManagers = kmf.getKeyManagers();
sslContext.init(keyManagers, null, null);
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
My ks has the required cert, even kmf has the required cert. But keyManager instance size is coming to be 0. It has nothing in it. Therefore the socketFactory sslParams also has a x509 keyManager which doesn't have any cert. Therefore my URLConnection doesn't present any cert and my connection fails.
Is there something wrong I'm doing?
Is it possible to restrict the application to use only specific TLS or SSL version ? Consider the backend web server supports all TLS or SSL version, let's say, if the OS is old and doesn't support newer versions, will the application fall back into the older one ?
Thanks for such a detailed explanation. It really helped !!
We are running into below issue :
Caused by: java.io.IOException: Wrong version of key store.
We are currently using 4.1.2 android version. Can you please guide us with this error.
Thanks,
Darshan