Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate on Android 4.x and 5.x

I am running my app on Android 4.4.2 and it throws this error:

07-03 08:43:59.255 21643-21803/com.myapp W/System.err: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at com.android.org.conscrypt.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:146)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:388)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:165)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at com.myapp.Util.Util$1.run(Util.java:242)
07-03 08:43:59.255 21643-21803/com.myapp W/System.err:     at java.lang.Thread.run(Thread.java:841)
07-03 08:43:59.475 21643-21643/com.myapp E/ViewRootImpl: sendUserActionEvent() mView == null

It works correctly on Android 6.x and above. Only Android 4.x and 5.x fail. I have not tried Android 3.x and below but I would be fine if I could only fix it for Android 4.x and 5.x. The interesting thing is that it used to work in the past and all of a sudden it stopped working without me changing the source code of the app. When I go to https://www.digicert.com/help/ to test my server SSL Certificate, everything passes:

DNS resolves <Domain> to <IP address>
HTTP Server Header: Apache

SSL certificate
Common Name =

Subject Alternative Names = <subdomain>.<Domain>, <Domain>, m.<Domain>, www.<Domain>

Issuer = COMODO RSA Extended Validation Secure Server CA

Serial Number = 5A34235B2A2B53B35354232B123B23C5

SHA1 Thumbprint = 98C357AC34A23B232134B2A4C23A2B23AC23A532

Key Length = 2048

Signature algorithm = SHA256 + RSA (excellent)

Secure Renegotiation: Supported

SSL Certificate has not been revoked
OCSP Staple:    Good
OCSP Origin:    Good
CRL Status: Good

SSL Certificate expiration
The certificate expires May 24, 2019 (325 days from today)

Certificate Name matches <Domain>

Subject 
Valid from 11/Jun/2017 to 24/May/2019
Issuer  COMODO RSA Extended Validation Secure Server CA


Subject COMODO RSA Extended Validation Secure Server CA
Valid from 12/Feb/2012 to 11/Feb/2027
Issuer  COMODO RSA Certification Authority


Subject COMODO RSA Certification Authority
Valid from 30/May/2000 to 30/May/2020
Issuer  AddTrust External CA Root
SSL Certificate is correctly installed
Congratulations! This certificate is correctly installed.

My SSL Certificate looks fine. I wonder why Android 4.x and 5.x are throwing this javax.net.ssl.SSLPeerUnverifiedException: No peer certificate error.

UPDATE 1: The SSL report shows that everything is fine with my SSL certificate. Why is Android complaining? This is the report:

enter image description here

I am using https://www.ssllabs.com/ssltest/

UPDATE 2: Reading https://developer.android.com/reference/javax/net/ssl/SSLPeerUnverifiedException.html#SSLPeerUnverifiedException(java.lang.String), what I understand is that the server was not able to identify itself. Why? I guess because in theory the server is missing the required peer certificate. It sounds like a contradiction if you see how when using https://www.ssllabs.com/ssltest/ in UPDATE 1, the SSL Report shows that my server passes certificate tests correctly.

UPDATE 3: My certificate authority (CA) is COMODO. My SSL report shows that everything is good with my SSL certificate: https://www.ssllabs.com/ssltest/analyze.html?d=cuponclub.net. When I make a server request from a web browser, everything is good: https://cuponclub.net/San-salvador/deals/json_index/. See how the HTTPS connection is successful, the certificate is valid from the browser and everything looks perfect. No errors on Android 6.x and above, but why is it that Android 4.x and 5.x keep complaining about my SSL certificate, throwing this error on the Android Studio logs when I try to compile my app on Android 4.x or 5.x?:

W/System.err: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
W/System.err:     at com.android.org.conscrypt.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:146)
W/System.err:     at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93)
W/System.err:     at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:388)
W/System.err:     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:165)
W/System.err:     at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
W/System.err:     at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
W/System.err:     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
W/System.err:     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
W/System.err:     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
W/System.err:     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
W/System.err:     at com.couponclub.Util.Util$1.run(Util.java:242)
W/System.err:     at java.lang.Thread.run(Thread.java:841)

UPDATE 4: Looking at the answers at Error in android application: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate, they suggest that the problem could be related to the Server Name Indication (SNI). When I use https://www.ssllabs.com/ssltest/ to analyze my site, I see this in the results in red:

Alternative names [................] MISMATCH Trusted No NOT TRUSTED Mozilla Apple Android Java Windows

Maybe my problem is related to this Server Name Indication (SNI) or the lack of it?

UPDATE 5: I am getting this "No SNI" in red from https://www.ssllabs.com/ssltest/. Maybe that is causing the problem?

enter image description here

UPDATE 6: Certificate #2 can be ignored for the effects of my question because it applies to a different domain. I only care about the results for Certificate #1.

UPDATE 7: The web hosting company support team and the SSL certificate issuer support team confirm that everything is fine with the SSL certificate and its installation, and they suggest this might be an issue about the Android SDK for Android 4.x and 5.x getting confused, and NOT an actual problem with the SSL certificate. Everything looks good with the SSL certificate.

UPDATE 8: I disabled TLS 1.1 and earlier on the server to comply with SSL standards and I am starting to suspect more that the cause of the bug is that Android 4.x and 5.x may expect to see libraries for support for TLS 1.1 and earlier and when it is not present, then it automatically throws an SSL error even though I do have TLS 1.2. That is one hypothesis that I have. For example, I was reading at https://help.salesforce.com/articleView?id=000231452&type=1 information about "Preparing mobile apps for TLS 1.0 deprecation" and they say this:

Android. Unfortunately, some work might be required to ensure that your Android applications don’t break when TLS 1.0 is disabled on a Salesforce instance. We have a fix that enforces TLS 1.1 and 1.2 on Mobile SDK Android applications.

So they were aware of the fact that disabling TLS 1.0 might make some Android apps to break for Salesforce instances, and they knew some work had to be done to fix that after disabling TLS 1.0. Similarly, I am starting to suspect that in my case, the problem could be the lack of support in my server for TLS 1.0 and earlier.

UPDATE 9: After I explained to COMODO CA support what I mentioned in UPDATE 8, this was their reply:

Thank you for contacting Comodo CA support. Android versions 4.3 and earlier do not support TLS 1.2. As you have enabled only TLS 1.2 on the server, no connections will be established to your server from those legacy devices. Certificate check happens only after establishing the connection.

UPDATE 10: Everything seems to indicate that what is happening to me is what is explained at https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/:

I recently had to work on an Android application that consumed an API which removed support for TLS 1.0 connections for security reasons. The Android documentation for SSLSocket says that TLS 1.1 and TLS 1.2 is supported within android starting API level 16+ (Android 4.1, Jelly Bean). But it is by default disabled but starting with API level 20+ (Android 4.4 for watch, Kitkat Watch and Android 5.0 for phone, Lollipop) they are enabled. But it is very hard to find any documentation about how to enable it for phones running 4.1 for example.

UPDATE 11: Looking at https://github.com/wireapp/wire-android/issues/1450, this is for example how wire.com, a popular collaboration platform, justifies the lack of support for Android 4.x:

Hi, thank you for your feedback. Unfortunately, upgrading to TLSv1.2 was a necessary step to increase the security of the communications between our servers and the clients, and it is not really something we are open to reconsider. As with all decisions that involve dropping support for older versions of something, there will be people whose devices will be left behind. However, given the gains in terms of security and given the very small number of people that will lose support, we made the decision to upgrade. Know that we're not alone in dropping support for TLS pre-1.2, as Github itself has done the same. On top of all these reasons, Android 4.x phones are quite old devices that most likely are not receiving any security updates from their manufacturers, so if you are a "privacy-aware" user I would recommend getting something more recent (Android 5 came out in 2014). We're sorry if you felt like you were left behind, but please understand that this decision was taken with security in mind as the most important factor.

UPDATE 12: Interesting link about what the problem is and what to try to fix it: https://medium.com/tech-quizlet/working-with-tls-1-2-on-android-4-4-and-lower-f4f5205629a. I already moved on as you can see in my answer to my own question, but maybe this link could be useful to somebody else.

like image 273
Jaime Montoya Avatar asked Jul 03 '18 15:07

Jaime Montoya


People also ask

What is SSL peer certificate?

Peer authentication means that the other side of the SSL connection is authenticated based on a trusted certificate installed locally. Alternatively, a Certification Authority (CA) certificate may be installed locally and the peer has a certificate signed by that authority.


2 Answers

From your description it looks like it's Android issue. Probably fixed in newer versions. If I would have to guess I would say that parsing of your certificate fails silently somewhere on Android side and after a moment when Android tries to getPeerCertificates() it throws exception because they were not initialized (due to the silent fail which I'm speculating about). Potentially if the fail is not silent you could try to find some stacktraces before your issue happens.

You could also try to workaround it by adjusting your site to be acceptable for old Android OS. I don't have good advice or solution but I would start with comparing your certificate with certificates from sites which are fine from old Android OS perspective.

like image 149
LLL Avatar answered Oct 09 '22 03:10

LLL


Cause: TLS 1.2 is disabled by default on Android 4.x. Solution: Since enabling TLS 1.2 is not as straightforward as defining in the build.gradle file the TLS version that I want to use, I decided to not support Android 4.x for my app, following the same justification that wire.com used and that I copied in UPDATE 11 of my question.

like image 30
Jaime Montoya Avatar answered Oct 09 '22 03:10

Jaime Montoya