Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9974dbb authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Move CustomTlsSocketFactory to cert4android so it can be used in other apps...

Move CustomTlsSocketFactory to cert4android so it can be used in other apps like ICSx⁵; update ical4android
parent 49fae858
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ dependencies {
    implementation 'com.squareup.okhttp3:logging-interceptor:3.12.1'
    implementation 'commons-io:commons-io:2.6'
    implementation 'dnsjava:dnsjava:2.1.8'
    implementation 'org.apache.commons:commons-lang3:3.8.1'
    //implementation 'org.apache.commons:commons-lang3:3.8.1'
    implementation 'org.apache.commons:commons-collections4:4.2'

    // for tests
+0 −128
Original line number Diff line number Diff line
/*
 * Copyright © Ricki Hirner (bitfire web engineering).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */

package at.bitfire.davdroid

import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import at.bitfire.cert4android.CustomCertManager
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.mockwebserver.MockWebServer
import org.apache.commons.io.IOUtils
import org.apache.commons.lang3.ArrayUtils.contains
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import java.net.Socket
import java.security.KeyFactory
import java.security.KeyStore
import java.security.Principal
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.security.spec.PKCS8EncodedKeySpec
import javax.net.ssl.SSLSocket
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509ExtendedKeyManager
import javax.net.ssl.X509TrustManager

class CustomTlsSocketFactoryTest {

    private lateinit var certMgr: CustomCertManager
    private lateinit var factory: CustomTlsSocketFactory
    private val server = MockWebServer()

    @Before
    fun startServer() {
        certMgr = CustomCertManager(getInstrumentation().context, false, true)
        factory = CustomTlsSocketFactory(null, certMgr)
        server.start()
    }

    @After
    fun stopServer() {
        server.shutdown()
        certMgr.close()
    }


    @Test
    fun testSendClientCertificate() {
        var public: X509Certificate? = null
        javaClass.classLoader!!.getResourceAsStream("sample.crt").use {
            public = CertificateFactory.getInstance("X509").generateCertificate(it) as? X509Certificate
        }
        assertNotNull(public)

        val keyFactory = KeyFactory.getInstance("RSA")
        val private = keyFactory.generatePrivate(PKCS8EncodedKeySpec(readResource("sample.key")))
        assertNotNull(private)

        val keyStore = KeyStore.getInstance("AndroidKeyStore")
        keyStore.load(null)
        val alias = "sample"
        keyStore.setKeyEntry(alias, private, null, arrayOf(public))
        assertTrue(keyStore.containsAlias(alias))

        val trustManagerFactory = TrustManagerFactory.getInstance("X509")
        trustManagerFactory.init(null as KeyStore?)
        val trustManager = trustManagerFactory.trustManagers.first() as X509TrustManager

        val factory = CustomTlsSocketFactory(object: X509ExtendedKeyManager() {
            override fun getServerAliases(p0: String?, p1: Array<out Principal>?): Array<String>? = null
            override fun chooseServerAlias(p0: String?, p1: Array<out Principal>?, p2: Socket?) = null

            override fun getClientAliases(p0: String?, p1: Array<out Principal>?) =
                    arrayOf(alias)

            override fun chooseClientAlias(p0: Array<out String>?, p1: Array<out Principal>?, p2: Socket?) =
                    alias

            override fun getCertificateChain(forAlias: String?) =
                    arrayOf(public).takeIf { forAlias == alias }

            override fun getPrivateKey(forAlias: String?) =
                    private.takeIf { forAlias == alias }
        }, trustManager)

        /* known client cert test URLs (thanks!):
        *  - https://prod.idrix.eu/secure/
        *  - https://server.cryptomix.com/secure/
        */
        val client = OkHttpClient.Builder()
                .sslSocketFactory(factory, trustManager)
                .build()
        client.newCall(Request.Builder()
                .get()
                .url("https://prod.idrix.eu/secure/")
                .build()).execute().use { response ->
            assertTrue(response.isSuccessful)
            assertTrue(response.body()!!.string().contains("CN=User Cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=CA"))
        }
    }

    @Test
    fun testUpgradeTLS() {
        val s = factory.createSocket(server.hostName, server.port)
        assertTrue(s is SSLSocket)
        val ssl = s as SSLSocket

        assertFalse(contains(ssl.enabledProtocols, "SSLv3"))
        assertTrue(contains(ssl.enabledProtocols, "TLSv1"))
        assertTrue(contains(ssl.enabledProtocols, "TLSv1.1"))
        assertTrue(contains(ssl.enabledProtocols, "TLSv1.2"))
    }


    private fun readResource(name: String): ByteArray {
        javaClass.classLoader!!.getResourceAsStream(name).use {
            return IOUtils.toByteArray(it)
        }
    }

}
+0 −24
Original line number Diff line number Diff line
-----BEGIN CERTIFICATE-----
MIIEEzCCAfsCAQEwDQYJKoZIhvcNAQEFBQAwRjELMAkGA1UEBhMCQ0ExEzARBgNV
BAgMClNvbWUtU3RhdGUxEDAOBgNVBAoMB0NBIENlcnQxEDAOBgNVBAMMB0NBIENl
cnQwHhcNMTgwMTEzMjAyOTI5WhcNMTkwMTEzMjAyOTI5WjBZMQswCQYDVQQGEwJD
QTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMRIwEAYDVQQDDAlVc2VyIENlcnQwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDqOyHAeG4psE/f6i/eTfwbhn6j7WaFXxZiSOWwpQZmzRrx
MrfkABJCk0X7KNgCaJcmBkG9G1Ri4HfKrxvJFswMXknlq+0ulGBk7oDnZM+pihuX
3D9VCWMMkCqYhLCGADj2zB2mkX4LpcMRi6XoOetKURE/vcIy7rSLAtJM6ZRdftfh
2ZxnautS1Tyujh9Au3NI/+Of80tT/nA+oBJQeT1fB/ga1OQlZP5kjSaA7IPiIbTz
QBO+r898MvqK/lwsvOYnWAp7TY03z+vPfCs0zjijZEl9Wrl0hW6o5db5kU1v5bcr
p87hxFJsGD2HIr2y6kvYfL2hn+h9iANyYdRnUgapAgMBAAEwDQYJKoZIhvcNAQEF
BQADggIBAHANsiJITedXPyp89lVMEmGY3zKtOqgQ3tqjvjlNt2sdPnj7wmZbmrNd
sa90S/UwOn8PzEFOVxYy1BPlljlEjtjmc4OHMcm4P4Zv36uawHilmK8V+zT59gCK
ftB5FP2TLFUFi2X9o8J06d0xJRE77uewN155NV4RmPuP4b/tMmeixoQppHqLqEr5
lgEUnt3Mh1ctmeFQFJR6lJ01hlB0gdpVHIhzrVLTO3uo8ePLJTmxP6tyKl/HXj9F
mpVsKb1kriKwbkGczfw99OUZeUVbTwQOR07r0SrG71B7IuDvxIORnhQc1OUjt7ob
wjdaZauAHxpGBRu+hw9Yqaxchk9Gldy1nEjGyyVCD0FU5taXbl8PhBWEDc4U9tI+
xVNmPpsSuCsbz3Mjd1YIVRGL99vLrKsQcj+TNM+jJKKRKes3ihl+l/0FwG6UuO7L
EvjlUg5hOtYi1D7xuYyMjroGBGh7swYMt6w4eCDbcjzcCkaCi0H2pScM/rLBpDjS
LIoGCvZ1LBdi933/iOj1/8dxGZwY6fEgcyiD2n0xAgYIniLWjEZXOMdIK5FNTNga
Tswanvp+6Noa4oIu/hl/LXvPMsouaWfSEbRe0Dshi3GpLj3YtEHoN9DHB8bn7jy5
34By81GT41m5kq3hWP//x9kSHYSADpbovCbKbElU1qSt6vTVR4nq
-----END CERTIFICATE-----
−1.19 KiB

File deleted.

Loading