22

I use the SSL Socket and Trustmanager from this side Self signed SSL

but i keep getting following error:

09-28 19:52:41.942: WARN/System.err(10101): javax.net.ssl.SSLHandshakeException: org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.

What is wrong? I already checked different posts on stackoverflow but i can`t seem to get it to work.

My code:

SchemeRegistry schemeRegistry = new SchemeRegistry();

// http scheme

schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

// https scheme

schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
params = new BasicHttpParams();
params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(1));
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf8");
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope("www.example.com", AuthScope.ANY_PORT),
    new UsernamePasswordCredentials("user", "password"));
clientConnectionManager = new ThreadSafeClientConnManager(params, schemeRegistry);
context = new BasicHttpContext();
context.setAttribute("http.auth.credentials-provider", credentialsProvider);

DefaultHttpClient client = new DefaultHttpClient(clientConnectionManager, params);

HttpGet get = new HttpGet("https://www.example.com/web/restricted/form/formelement=512663");
HttpResponse response = client.execute(get, context);

Log.w("Response ","Status line : "+ response.toString());
Kenster
  • 23,465
  • 21
  • 80
  • 106
Lars
  • 915
  • 4
  • 18
  • 27
  • 21
    You may also want to check the date and time settings on the phone. If the clocks are too far out of sync you can get similar errors to this. – Michael Levy Feb 27 '12 at 20:19
  • If you use `Fuel` as a REST library, see https://stackoverflow.com/questions/47460211/kotlin-library-that-can-do-https-connection-without-certificate-verification-li/54276837. – CoolMind Jan 21 '19 at 11:51

6 Answers6

36

As Michael Levy mentioned, the reason I was getting this exception is that I had left my Android Emulator open for a few days and the clock had gotten pretty far out of sync. Once I restarted the emulator, the exception went away.

Adam Johns
  • 35,397
  • 25
  • 123
  • 176
  • 2
    I had a similar issue on a physical Galaxy Note device with no SIM. Interestingly, the built in browser worked fine. Once I updated the time sync settings to automatic, I no longer experienced any errors. – Stephen Niedzielski Feb 28 '15 at 22:13
  • 3
    True, I was facing issue with the certificate handshake and had found that my device time was not properly set. It was set to somethings in past and ssl handshake failed. – Haresh Chaudhary Nov 30 '15 at 20:11
3

UPDATE

I also got another error on API 16 emulator:

routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741'.

Reading 1 and 2, I changed code so:

val okHttpClient = getOkHttpBuilder().build()

private fun getOkHttpBuilder(): OkHttpClient.Builder {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        Security.insertProviderAt(Conscrypt.newProvider(), 1)
    }
    return OkHttpClient().newBuilder()
}

// build.gradle:
implementation 'org.conscrypt:conscrypt-android:2.5.1'

But the library adds 3.4 Mb to apk.

I also removed these lines from MyApplication:

try {
    ProviderInstaller.installIfNeeded(applicationContext)
    val sslContext = SSLContext.getInstance("TLSv1.2")
    sslContext.init(null, null, null)
    sslContext.createSSLEngine()
} catch (e: GooglePlayServicesRepairableException) {
    Timber.e(e.stackTraceToString())
    // Prompt the user to install/update/enable Google Play services.
    GoogleApiAvailability.getInstance().showErrorNotification(this, e.connectionStatusCode)
} catch (e: GooglePlayServicesNotAvailableException) {
    Timber.e(e.stackTraceToString())
    // Prompt the user to install/update/enable Google Play services.
    // GoogleApiAvailability.getInstance().showErrorNotification(this, e.errorCode)
} catch (e: NoSuchAlgorithmException) {
    Timber.e(e.stackTraceToString())
} catch (e: KeyManagementException) {
    Timber.e(e.stackTraceToString())
}

=== Old answer ===

In my case a following error raised on Android 4 and 5:

Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate expired at Sat May 30 10:48:38 GMT+00:00 2020 (compared to Thu Aug 13 11:47:00 GMT+00:00 2020)

...

Caused by: java.security.cert.CertificateExpiredException: Certificate expired at Sat May 30 10:48:38 GMT+00:00 2020 (compared to Thu Aug 13 11:47:00 GMT+00:00 2020)

The server has certificate error (probably expired).

For Retrofit see https://stackoverflow.com/a/60507560/2914140. If you use Fuel as a REST library, see kotlin library that can do httpS connection without certificate verification (like curl --insecure).

You can trust all certificates, but it's dangerous.

import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.security.cert.CertificateException

companion object {

    private val gson: Gson
    private val retrofit: Retrofit

    init {

        val okHttpClient = getOkHttpBuilder().build()

        gson = GsonBuilder().setLenient().create()

        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
    }

    private fun getOkHttpBuilder(): OkHttpClient.Builder =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            OkHttpClient().newBuilder()
        } else {
            getUnsafeOkHttpClient()
        }

    private fun getUnsafeOkHttpClient(): OkHttpClient.Builder =
        try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts: Array<TrustManager> = arrayOf(
                object : X509TrustManager {
                    @Throws(CertificateException::class)
                    override fun checkClientTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
                }
            )
            // Install the all-trusting trust manager
            val sslContext: SSLContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())
            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory,
                trustAllCerts[0] as X509TrustManager)
            builder.hostnameVerifier { _, _ -> true }
            builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
}

See also https://stackoverflow.com/a/60507560/2914140 for Android version check and Glide connection.

CoolMind
  • 26,736
  • 15
  • 188
  • 224
  • I have exactly the same error on Crashlytics for Android 4 and 5, but I'm still quite puzzled on why it happens and why only on these 2 OS. – VGM Aug 29 '20 at 16:20
  • @VGM, thanks! As I understood after months of appearing-disappearing problems with a certificate, in Android 4 and 5 it cannot establish connection via new protocols by default. So, we need to enable SSL, TLS 1.2, 1.3. You know, it was difficult for me, so I just removed trusting. I don't know whether it works on all old devices, but in emulators and some devices removing trusting works. – CoolMind Aug 31 '20 at 07:36
2

Most probably server returned certificate chain with authorities you do not trust. (means: authority certificates are not known to your device as trusted) Solution: carefully examine certificates coming from HTTPS website, and add respective authorities to your truststore - but this part seems to be tricky

( here some explanations : http://groups.google.com/group/android-security-discuss/browse_thread/thread/0bf726de4f5275a3/391b900631d7f358 )

Konstantin Pribluda
  • 12,329
  • 1
  • 30
  • 35
  • Hi Konstantin, Thx for the reply but i think i have to login to this site another way, this is too complicated. The site i want to login has a login form which can be submitted through HTTP, the login is then authenticated and redirects through SSL to the page i want. I think a HTTP Post with preserved cookies from a HTTPGet should do it or? – Lars Sep 28 '11 at 20:06
  • You did not make it that far - you never get HTTPS connection. You may succeed by submiting HTTP form, but redirect over SSH will not work unless you sort certificate problem - It's your side which does not trust the server. Funny thing is, that some servers are buggy and just can not verify signatures of clients (notably JBoss had this bug) – Konstantin Pribluda Sep 29 '11 at 06:55
1

Check the time of your device, correct it and then check again.

Nico Müller
  • 1,784
  • 1
  • 17
  • 37
Abdul Hanan
  • 93
  • 1
  • 7
0

BTW,we could re-produce this error easily -- just change the date of the phone to several years later.

NOTE: the error might be a little difference in different phone. Some might show that the certificate has expired.

civic.LiLister
  • 2,087
  • 16
  • 13
0

Looks like wrong date/time of the device

AmigoPal
  • 39
  • 1
  • 4
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 21 '22 at 11:53