3

I have the following kotlin code:

val urlPath = "https://10.0.2.2:8080"
var data: String
try {
    data = URL(urlPath).readText()
} catch (e: Exception) {
    Log.e("doInBackground", "Exception caught: ${e.localizedMessage}")
    error = when (e) {
        is MalformedURLException -> "Invalid URL"
        is IOException -> "Network Error"
        else -> {
            "Network error: ${e.localizedMessage}"
        }
    }
}

If I use the above code to connect to a http server, the above code works. However when I try to connect to a https server with a self-signed certificate, it fails. Is there a way to allow https connections on localhost (only), even when the certificates are self-signed ?

Todd
  • 30,472
  • 11
  • 81
  • 89
Sankar
  • 6,192
  • 12
  • 65
  • 89
  • Does the server only allow mutual authentication? Otherwise, you only need to trust the presented server certificate with a custom TrustStore – s1m0nw1 Feb 28 '18 at 15:31
  • It is a simple golang https server started via http.ListenAndServerTLS and so there is nothing extra configured for mutual authentication. How do I create a TrustStore using the kotlin extension on URL ? I can't find any code sample for that from google easily. – Sankar Feb 28 '18 at 16:10
  • It’s not Kotlin specific, google for Java JSSE – s1m0nw1 Feb 28 '18 at 16:11

1 Answers1

3

Here's an example that reads from https://google.com using JSSE, it trusts literally every certificate and shouldn't be used productively.

fun main(args: Array<String>) {
    val urlPath = "https://google.com"
    try {
        (URL(urlPath).openConnection() as HttpsURLConnection).apply {
            sslSocketFactory = createSocketFactory(listOf("TLSv1.2"))
            hostnameVerifier = HostnameVerifier { _, _ -> true }
            readTimeout = 5_000
        }.inputStream.use {
            it.copyTo(System.out)
        }
    } catch (e: Exception) {
        TODO()
    }
}


private fun createSocketFactory(protocols: List<String>) =
    SSLContext.getInstance(protocols[0]).apply {
        val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
            override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
            override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) = Unit
            override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) = Unit
        })
        init(null, trustAllCerts, SecureRandom())
    }.socketFactory

I've got a little library for these kinds of things here, which is neither up-to-date nor published. Nevertheless, it provides a simple DSL for setting up TLS/SSL sockets and provides means for https connections.

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
  • This does not seem to work. I still get an exception: `03-01 00:09:27.667 5028-5088/com.example.logindemo E/doInBackground: Exception caught: Failed to connect to /10.0.2.2:8080` – Sankar Mar 01 '18 at 05:10
  • Well that exception isn’t really helpful to me – s1m0nw1 Mar 01 '18 at 05:26
  • ah wait. It was a mistake on my end (started the server on a wrong port). The code works fine. I will accept the answer. However, I request that you consider editing the code to ignore certificate checks only for "localhost" (and probably 10.0.2.2 too to cover for Android) only and not a blanket open-for-all. Thanks. – Sankar Mar 01 '18 at 05:45
  • can someone please send me a source from which I can enderstand what is going on? altough it solved my problem, I dont understand how it did and would really love to know whats going on in detailed.. – eitan 03 Dec 07 '19 at 15:39