Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'No peer certificate' error in Android 2.3 but NOT in 4

Tags:

Getting the "javax.net.ssl.SSLPeerUnverifiedException: No peer certificate error" in an emulator running Android 2.3 but NOT in 4. In 4 it works perfectly. I'm trying to connect to a live server via https. It uses a valid Thawte certificate, works fine in all browsers and Android 3 and 4.

If anyone has code help, PLEASE and thanks. Also, if anyone has any suggestions on a secure workaround, I'd appreciate it. I'm still learning, and I've been on this problem for a week. It has to end, so I can continue working and learning. Urgh.

Here is HttpCLient code, courtesy Antoine Hauck (http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/):

 import java.io.InputStream;     import java.security.KeyStore;     import java.security.cert.CertificateException;      import javax.net.ssl.SSLContext;     import javax.net.ssl.TrustManager;     import javax.net.ssl.X509TrustManager;     import javax.security.cert.X509Certificate;      import org.apache.http.conn.ClientConnectionManager;     import org.apache.http.conn.scheme.PlainSocketFactory;     import org.apache.http.conn.scheme.Scheme;     import org.apache.http.conn.scheme.SchemeRegistry;     import org.apache.http.conn.ssl.SSLSocketFactory;     import org.apache.http.impl.client.DefaultHttpClient;     import org.apache.http.impl.conn.SingleClientConnManager;      import android.content.Context;      public class MyHttpClient extends DefaultHttpClient {      final Context context;      public MyHttpClient(Context context) {         this.context = context;     }      @Override     protected ClientConnectionManager createClientConnectionManager() {         SchemeRegistry registry = new SchemeRegistry();         registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));         // Register for port 443 our SSLSocketFactory with our keystore         // to the ConnectionManager         registry.register(new Scheme("https", newSslSocketFactory(), 443));         return new SingleClientConnManager(getParams(), registry);     }      private SSLSocketFactory newSslSocketFactory() {          try {              // Get an instance of the Bouncy Castle KeyStore format              KeyStore trusted = KeyStore.getInstance("BKS");              // Get the raw resource, which contains the keystore with              // your trusted certificates (root and any intermediate certs)              InputStream in = context.getResources().openRawResource(R.raw.my_cert);              try {                  // Initialize the keystore with the provided trusted certificates                  // Also provide the password of the keystore                  trusted.load(in, "my_pass".toCharArray());              } finally {                  in.close();              }              // Pass the keystore to the SSLSocketFactory. The factory is responsible             // for the verification of the server certificate.             SSLSocketFactory sf = new SSLSocketFactory(trusted);             // Hostname verification from certificate             // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506             sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);             return sf;         } catch (Exception e) {             throw new AssertionError(e);         }     } } 

And here is the code that instantiates it:

DefaultHttpClient client = new MyHttpClient(getApplicationContext());             HttpPost post = new HttpPost(server_login_url);            List <NameValuePair> parameters = new ArrayList <NameValuePair>();            parameters.add(new BasicNameValuePair("username", user));            parameters.add(new BasicNameValuePair("password", pass));              try {                post.setEntity(new UrlEncodedFormEntity(parameters, HTTP.UTF_8));             } catch (UnsupportedEncodingException e2) {                 // TODO Auto-generated catch block                 Log.d(DEBUG_TAG, "in  UnsupportedEncodingException - " + e2.getMessage());                 e2.printStackTrace();             }                 // Execute the GET call and obtain the response            HttpResponse getResponse = null;              try {                 getResponse = client.execute(post);             } catch (ClientProtocolException e) {                 // TODO Auto-generated catch block                 // Toast.makeText(getBaseContext(),message,Toast.LENGTH_LONG).show();                 Log.d(DEBUG_TAG, "in ClientProtocolException - " + e.getMessage());             } catch (IOException e) {                 // TODO Auto-generated catch block                 // Toast.makeText(getBaseContext(),message,Toast.LENGTH_LONG).show();                 Log.d(DEBUG_TAG, "in  client.execute IOException - " + e.getMessage());                 e.printStackTrace();             } 

The error is caught in the IOException block. Here is the stack:

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:258) org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93) org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381) org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164) org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359) org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) org.ffb.tools.SplashActivity$LoginTask.makeConnection(SplashActivity.java:506) org.ffb.tools.SplashActivity$LoginTask.doLogin(SplashActivity.java:451) org.ffb.tools.SplashActivity$LoginTask.doInBackground(SplashActivity.java:439) org.ffb.tools.SplashActivity$LoginTask.doInBackground(SplashActivity.java:1) android.os.AsyncTask$2.call(AsyncTask.java:185) java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306) java.util.concurrent.FutureTask.run(FutureTask.java:138) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581) java.lang.Thread.run(Thread.java:1019) 

Here is the chain order (from openssl command):

The chain looks good I think.

    i:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA   1 s:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA   i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized      use only/CN=thawte Primary Root CA   2 s:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For      authorized use only/CN=thawte Primary Root CA   i:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services      Division/CN=Thawte Premium Server CA/[email protected] 
like image 291
user1214401 Avatar asked Mar 05 '12 22:03

user1214401


People also ask

How do I fix certificate not trusted error?

To resolve this problem, install the intermediate certificate (or chain certificate) file to the server that hosts your website. To do that, log into your DigiCert Management Console, click the order number, and then select the certificate download link. This file should be named DigiCertCA.

Why does my phone say certificate not trusted?

This most likely reason you're getting a certificate not secure error message for your email is that you've synced an email account that belongs to a domain that you/your organization owns but there's a mismatch in the SMTP/IMAP settings, port settings, or domain name settings.


1 Answers

This thread was really helpful when I debugged a similar issue.

Summary Android 2.3 HTTPS/SSL checklist:

  • If your CA is in Android's 2.3 list of trusted CA's -- and Thawte is -- there's no need to include the certificate in the app.
  • Android 2.3 does not support Server Name Indication so if your server is relying on it for SSL handshaking, Android may not be getting the certificates you're expecting.
  • Do you have certificate chain on the server installed, and is it ordered correctly? Most browsers handle out-of-order certificate chains but Android 2.3 does not. bdc's answer in the thread I mentioned above describes how to check the validity of your SSL certificate and chain with "openssl s_client -connect yourserver.com:443".
  • When digging up that old 2.3 device you have in your bottom drawer, please ensure its date and time are set correctly after being powerless for too long.
like image 161
Ed Holzwarth Avatar answered Sep 20 '22 15:09

Ed Holzwarth