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]
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.
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.
This thread was really helpful when I debugged a similar issue.
Summary Android 2.3 HTTPS/SSL checklist:
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