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

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

Add test

parent fa58cc80
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line

buildscript {
    ext.kotlin_version = '1.3.20'
    ext.kotlin_version = '1.3.21'
    ext.dokka_version = '0.9.17'

    repositories {
@@ -9,7 +9,7 @@ buildscript {
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.0'
        classpath 'com.android.tools.build:gradle:3.3.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:${dokka_version}"
    }
@@ -51,6 +51,9 @@ dependencies {

    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test:rules:1.1.1'
    androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
    androidTestImplementation 'commons-io:commons-io:2.6'
    androidTestImplementation 'org.apache.commons:commons-lang3:3.8.1'

    testImplementation 'junit:junit:4.12'
}
+127 −0
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.cert4android

import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
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 CertTlsSocketFactoryTest {

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

    @Before
    fun startServer() {
        certMgr = CustomCertManager(getInstrumentation().context, false, true)
        factory = CertTlsSocketFactory(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 = CertTlsSocketFactory(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)
        }
    }

}
+24 −0
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 added.

No diff preview for this file type.