Commit e3f33a56 authored by Ricki Hirner's avatar Ricki Hirner 🐑

Test for client certificates

parent 702888e9
/*
* 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 android.support.test.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 {
lateinit var certMgr: CustomCertManager
lateinit var factory: CustomTlsSocketFactory
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 {
this.javaClass.classLoader.getResourceAsStream(name).use {
return IOUtils.toByteArray(it)
}
}
}
/*
* 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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import at.bitfire.cert4android.CustomCertManager;
import okhttp3.mockwebserver.MockWebServer;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static junit.framework.TestCase.assertFalse;
import static org.apache.commons.lang3.ArrayUtils.contains;
import static org.junit.Assert.assertTrue;
public class SSLSocketFactoryCompatTest {
CustomCertManager certMgr;
CustomTlsSocketFactory factory;
MockWebServer server = new MockWebServer();
@Before
public void startServer() throws Exception {
certMgr = new CustomCertManager(getInstrumentation().getContext(), false, true);
factory = new CustomTlsSocketFactory(null, certMgr);
server.start();
}
@After
public void stopServer() throws Exception {
server.shutdown();
certMgr.close();
}
@Test
public void testUpgradeTLS() throws IOException {
Socket s = factory.createSocket(server.getHostName(), server.getPort());
assertTrue(s instanceof SSLSocket);
SSLSocket ssl = (SSLSocket)s;
assertFalse(contains(ssl.getEnabledProtocols(), "SSLv3"));
assertTrue(contains(ssl.getEnabledProtocols(), "TLSv1"));
assertTrue(contains(ssl.getEnabledProtocols(), "TLSv1.1"));
assertTrue(contains(ssl.getEnabledProtocols(), "TLSv1.2"));
}
}
-----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-----
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment