title: 'No peer certificate' error in Android 2.3 but NOT in 4
body: <p>Getting the <code>"javax.net.ssl.SSLPeerUnverifiedException: No peer certificate error"</code> 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.</p>
  
  <p>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.</p>
  
  <p>Here is HttpCLient code, courtesy Antoine Hauck (<a href="http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/" rel="noreferrer">http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/</a>):</p>
  
  <pre><code> 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);
          }
      }
  }
  </code></pre>
  
  <p>And here is the code that instantiates it:</p>
  
  <pre><code>DefaultHttpClient client = new MyHttpClient(getApplicationContext());
  
             HttpPost post = new HttpPost(server_login_url);
             List &lt;NameValuePair&gt; parameters = new ArrayList &lt;NameValuePair&gt;();
             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();
              }
  </code></pre>
  
  <p>The error is caught in the IOException block. Here is the stack:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>Here is the chain order (from openssl command):</p>
  
  <p>The chain looks good I think.</p>
  
  <pre><code>    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/emailAddress=premium-server@thawte.com
  </code></pre>