4

This thing has been bugging me for couple days now. I've read lots of other questions about this whole issue and still haven't been able to proceed.

I've created a simple test application just to test SSL on Android. The application has only one button and when clicked the application tries to send "Hello World" over SSL encrypted connection to my test server, which then responds with the exact same phrase.

First I created a test key and test certificate for my server using openssl. Then I've been following the instructions showed in Crazy Bob's blog. I got the Bouncy Castle provider directly from Bouncy Castle's site, created a trusted keystore as shown on Crazy Bob's blog and got everything right at that point I believe.

When I tried to run my code, I got the exception "IOException: Wrong version of key store." Then I found this question on StackOverflow. There it was suggested that I should try using older Bouncy Castle Providers rather than the newest bcprov-jdk15on-147.jar. I went on with this in mind and actually ended up trying every bcprovider from jdk13-146 to jdk16-146. Still every time I got the same "IOExcpetion: wrong version of key store." exception.

Then I found yet another question about similar problem on StackOverflow. There someone had managed to get rid of that exception by using 512 bit sized key instead of 1024 sized key. Well I gave it a try and accomplished nothing, but the same exception.

So here I am now, wondering what to do next. I'm pretty much running out of ideas and google search results.

My web code is 1 on 1 copy of crazy bob's code and besides that the application has only the activity class that handles the button only. I'm trying to implement this on API level 7.

Any help would be greatly appreciated. Thanks.

Community
  • 1
  • 1
zaplec
  • 1,681
  • 4
  • 23
  • 51
  • If you move your target API to something like 10 or 14 does it start working? When working on older API levels it's not a bad idea to test on newer ones just to ensure it's not a compatibility issue. – matt5784 Jun 01 '12 at 13:55
  • I need to create ".pem"file for my Android project for brain tree. I installed openssl and run the following cmd: openssl> s_client -connect $https://xxx.xxx.xx:443 2>&1 | \ sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem but i get error in s_client. please help me. I get the command from Crazy Bob's blog. – M.A.Murali Nov 22 '13 at 11:20

3 Answers3

2

2 choices:

  1. You can do what you do and create your own key store and I've done that, here is instructions from my code that I stored (because it was so time consuming to get it to work):

    To generate PKS:

    1. Created cert in IIS7 and then exported as pfx. Follow instruction on SelfSSL: http://www.robbagby.com/iis/self-signed-certificates-on-iis-7-the-easy-way-and-the-most-effective-way/ 1a. Download tool: http://cid-3c8d41bb553e84f5.skydrive.live.com/browse.aspx/SelfSSL 1b. Run: SelfSSL /N:CN=mydomainname /V:1000 /S:1 /P:8081 I use port 8181 on my server 1c. Export from IIS manager to cert.pfx
    2. Run command line in SSL to convert file into X.509: openssl pkcs12 -in C:\cert.pfx -out C:\cert.cer -nodes
    3. Edit file and delete all except -----BEGIN.... END CERTIFICATE----- IMPORTANT! It was working when I got proper (5) amount of dashes and put tags and data on separate lines
    4. use keytool. C:\Java\JDK\bcprov.jar was downloaded separately C:\Users>keytool -import -v -trustcacerts -alias key_alias -file C:\cert.cer -keystore C:\mystore.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath C:\Java\JDK\bcprov.jar -storepass 123456
  2. Create TRUST ALL KeyStore and forget about all this. Basically, you can use any SSL without errors. Just disable it in production if you really care. Here is code I use to get SSL client prepared (assuming you use Apache Http client)

    private HttpClient getHttpClient()
    {
        HttpParams params = new BasicHttpParams();
    
        //Set main protocol parameters
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
        HttpProtocolParams.setUseExpectContinue(params, true);
    
        // Turn off stale checking.  Our connections break all the time anyway, and it's not worth it to pay the penalty of checking every time.
        HttpConnectionParams.setStaleCheckingEnabled(params, false);
        // FIX v2.2.1+ - Set timeout to 30 seconds, seems like 5 seconds was not enough for good communication
        HttpConnectionParams.setConnectionTimeout(params, 30 * 1000);
        HttpConnectionParams.setSoTimeout(params, 30 * 1000);
        HttpConnectionParams.setSocketBufferSize(params, 8192);
    
        // Don't handle redirects -- return them to the caller.  Our code often wants to re-POST after a redirect, which we must do ourselves.
        HttpClientParams.setRedirecting(params, false);
    
        // Register our own "trust-all" SSL scheme
        SchemeRegistry schReg = new SchemeRegistry();
        try
        {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
    
            TrustAllSSLSocketFactory sslSocketFactory = new TrustAllSSLSocketFactory(trustStore);
            sslSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
            Scheme sslTrustAllScheme = new Scheme("https", sslSocketFactory, 443);
            schReg.register(sslTrustAllScheme);
        }
        catch (Exception ex)
        {
            LogData.e(LOG_TAG, ex, LogData.Priority.None);
        }
    
        ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg);
        return new DefaultHttpClient(conMgr, params);
    }
    
petey
  • 16,914
  • 6
  • 65
  • 97
katit
  • 17,375
  • 35
  • 128
  • 256
  • If I use the TRUST ALL option, does it mean that my app is the only one that trusts all sites? In other words, I'm just trying to make sure that it wont affect other applications on phone in any way. The URL my application is using, is hard coded as it never changes and therefore it might be safe to allow the application to trust all sites as it would never ever try to connect to some "non-trusted" site. – zaplec Jun 13 '12 at 11:43
  • Yes, you only set it to trust all certificates for this particular connection. Other apps won't be affected – katit Jun 13 '12 at 13:12
  • This trust all solution works, but it leaves possible applications still vulnerable to man-in-the-middle attacks. For testing purposes it's OK, but I think I need to continue my struggle for getting the SSL work with only one trusted site :) – zaplec Jun 14 '12 at 08:10
  • I gave you instructions in #1. It was working for me. I switched for trust all later because men in the middle is not an issue for me – katit Jun 14 '12 at 10:42
  • Yeah, I checked your instructions at #1, but i'm still getting that "Wrong version of key store" exception, even if I follow the instructions you gave. I'll change to Java 1.6 or Java 1.5 and try again, because so far I've been using Java 1.7. Hopefully that helps. – zaplec Jun 14 '12 at 11:15
0

It is similar my question when I try to request to EWS. You can refer to this link and download example source code then modify it like my answer. Hope this helps!

Update:
The following command worked for me (I tried it about 2 months ago):

  C:\OpenSSL-Win32\bin>keytool -importcert -v -trustcacerts -file "d:/cer.cer" 
  -alias parkgroup_restful -keystore "D:/parkgroup-ws-client.bks" 
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath 
 "D:/bcprov-jdk16-145.jar" -storetype BKS -storepass 1234567

  .... /**It should show the result here**/

   Trust this certificate? [no]:  yes
   Certificate was added to keystore
   [Storing D:/parkgroup-ws-client.bks]

   C:\OpenSSL-Win32\bin>keytool -list -keystore "D:/parkgroup-ws-client.bks" -provi
   der org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "D:/bcprov-
   jdk16-145.jar" -storetype BKS -storepass 1234567

   Keystore type: BKS
   Keystore provider: BC

   Your keystore contains 1 entry

   parkgroup_restful, Apr 10, 2012, trustedCertEntry,
   Certificate fingerprint (MD5): 36:47:88:62:23:1C:F3:52:17:BE:7A:A9:94:56:19:18

You can see, I use bcprov-jdk16-145.jar and openssl lib. You can try it.
Another tool to create keystore: http://portecle.sourceforge.net/

Community
  • 1
  • 1
ductran
  • 10,043
  • 19
  • 82
  • 165
  • Thanks for the links, but still couldn't get over the "Wrong version of key store" exception. – zaplec Jun 08 '12 at 10:48
  • I'm not sure if I really get what you are doing with the first line as it seems to me that you are never using the PEM you are creating there. Can you explain it a bit? Otherwise your solution seems pretty much like what I have tried. I have tried bcprov-jdk16-145.jar (plus other versions) and openssl as well. – zaplec Jun 11 '12 at 11:29
  • I recommend you check your certificate file because I got the same your problem. Then I try to use another file, it worked. – ductran Jun 12 '12 at 02:58
0

Well I also faced this same situation and to solve it I took help from same blog post(http://nelenkov.blogspot.in/2011/12/using-custom-certificate-trust-store-on.html) referred by R4j. Following are the steps involved :

  1. Create custom trustore : I used Portecle to create a keystore and imported Public Key Certificate from my server into it.
  2. Create custom keystore with keypair : keytool -genkeypair -alias sample -keyalg RSA -sigalg SHA1withRSA -dname "CN=Nazgul, OU=Assault, O=Sauron Enterprises, L=Mordor, ST=Middle Earth, C=ME" -keypass welcome123 -validity 365 -storetype pkcs12 -keystore g:\mordor_key_store.pfx -storepass welcome123 -keysize 2048
  3. You then use them as mentioned in nelkov's blog. You may also need to create your own custom AbstractVerifier in case you land into a situation where certificate is issued for abc.com and the Verifier rejects www.abc.com
  4. Finally to create secure HTTPClient you can do something like this:

            public static DefaultHttpClient getSecureHttpClient(){
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        SSLContext sslContext = null;
        try {
            sslContext = createSslContext(true);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        final X509HostnameVerifier delegate = new BrowserCompatHostnameVerifier();
        MySSLSocketFactory socketFactory = new MySSLSocketFactory(sslContext, delegate);
        schemeRegistry.register(new Scheme("https", socketFactory, 443));
    
        DefaultHttpClient client = new DefaultHttpClient();
        HttpParams params = client.getParams();
        client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
                schemeRegistry), params){
            protected HttpParams determineParams(HttpRequest req) {
                HttpParams params = req.getParams(); // req is an HttpRequest object
                HttpConnectionParams.setSoTimeout(params, 60000);
                HttpConnectionParams.setConnectionTimeout(params, 60000);
                return params;
            }
        };
    
        return client;
    }
    

For detailed reasons of my choices you can refer to this post http://fuking-android.quora.com/Implement-HTTPS-for-android-apps-a-novices-tale.

venom.unleashed
  • 831
  • 7
  • 6