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

Initial transformation to Kotlin

parent 9033f39d
Pipeline #8747839 passed with stage
in 4 minutes and 17 seconds
buildscript {
ext.kotlin_version = '1.1.2-4'
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
jcenter()
maven {
url 'http://oss.sonatype.org/content/repositories/snapshots'
}
}
repositories {
jcenter()
mavenCentral()
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 25
......@@ -41,6 +40,7 @@ android {
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
compile 'com.android.support:appcompat-v7:25.+'
compile 'com.android.support:cardview-v7:25.+'
......
......@@ -101,7 +101,7 @@ public class CustomCertManagerTest {
paranoidCertManager.checkServerTrusted(siteCerts, "RSA");
}
/* fails randomly (in about 1 of 3 cases) for unknown reason:
// fails randomly (in about 1 of 3 cases) for unknown reason:
@Test(expected = CertificateException.class)
public void testRemoveCustomCertificate() throws CertificateException, TimeoutException, InterruptedException {
addCustomCertificate();
......@@ -115,7 +115,6 @@ public class CustomCertManagerTest {
startService(intent, CustomCertService.class);
paranoidCertManager.checkServerTrusted(siteCerts, "RSA");
}
*/
private void addCustomCertificate() throws TimeoutException, InterruptedException {
// add certificate and check again
......
/*
* 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 android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.logging.Level;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class CertUtils {
@Nullable
public static X509TrustManager getTrustManager(@Nullable KeyStore keyStore) {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(keyStore);
for (TrustManager trustManager : tmf.getTrustManagers())
if (trustManager instanceof X509TrustManager)
return (X509TrustManager)trustManager;
} catch(NoSuchAlgorithmException|KeyStoreException e) {
Constants.log.log(Level.SEVERE, "Couldn't initialize trust manager", e);
}
return null;
}
@NonNull
public static String getTag(@NonNull X509Certificate cert) {
StringBuilder sb = new StringBuilder();
for (byte b: cert.getSignature())
sb.append(String.format("%02x", b & 0xFF));
return sb.toString();
}
}
/*
* 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 java.security.GeneralSecurityException
import java.security.KeyStore
import java.security.cert.X509Certificate
import java.util.logging.Level
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
class CertUtils {
companion object {
@JvmStatic
fun getTrustManager(keyStore: KeyStore?): X509TrustManager? {
try {
val tmf = TrustManagerFactory.getInstance("X509")
tmf.init(keyStore)
for (trustManager in tmf.trustManagers)
if (trustManager is X509TrustManager)
return trustManager
} catch(e: GeneralSecurityException) {
Constants.log.log(Level.SEVERE, "Couldn't initialize trust manager", e)
}
return null;
}
@JvmStatic
fun getTag(cert: X509Certificate): String {
val str = StringBuilder()
for (b in cert.signature)
str.append(String.format("%02x", b))
return str.toString()
}
}
}
......@@ -6,14 +6,18 @@
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.cert4android;
package at.bitfire.cert4android
import java.util.logging.Logger;
import java.util.logging.Logger
public class Constants {
class Constants {
companion object {
public static Logger log = Logger.getLogger("cert4android");
@JvmField
var log: Logger = Logger.getLogger("cert4android")
public static int NOTIFICATION_CERT_DECISION = 88809;
@JvmField
val NOTIFICATION_CERT_DECISION = 88809
}
}
/*
* 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 android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.util.LinkedList;
import java.util.List;
public class TrustCertificateActivity extends AppCompatActivity {
public static final String EXTRA_CERTIFICATE = "certificate";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_trust_certificate);
showCertificate();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
showCertificate();
}
protected void showCertificate() {
X509Certificate cert = (X509Certificate)getIntent().getSerializableExtra(EXTRA_CERTIFICATE);
final String subject;
try {
if (cert.getIssuerAlternativeNames() != null) {
StringBuilder sb = new StringBuilder();
for (List altName : cert.getSubjectAlternativeNames()) {
Object name = altName.get(1);
if (name instanceof String)
sb .append("[").append(altName.get(0)).append("]")
.append(name).append(" ");
}
subject = sb.toString();
} else
subject = cert.getSubjectDN().getName();
TextView tv = (TextView)findViewById(R.id.issuedFor);
tv.setText(subject);
tv = (TextView)findViewById(R.id.issuedBy);
tv.setText(cert.getIssuerDN().toString());
DateFormat formatter = DateFormat.getDateInstance(DateFormat.LONG);
tv = (TextView)findViewById(R.id.validity_period);
tv.setText(getString(R.string.trust_certificate_validity_period_value,
formatter.format(cert.getNotBefore()),
formatter.format(cert.getNotAfter())));
tv = (TextView)findViewById(R.id.fingerprint_sha1);
tv.setText(fingerprint(cert, "SHA-1"));
tv = (TextView)findViewById(R.id.fingerprint_sha256);
tv.setText(fingerprint(cert, "SHA-256"));
} catch(CertificateParsingException e) {
e.printStackTrace();
}
final Button btnAccept = (Button)findViewById(R.id.accept);
CheckBox cb = (CheckBox)findViewById(R.id.fingerprint_ok);
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean state) {
btnAccept.setEnabled(state);
}
});
}
public void acceptCertificate(View view) {
sendDecision(true);
finish();
}
public void rejectCertificate(View view) {
sendDecision(false);
finish();
}
protected void sendDecision(boolean trusted) {
Intent intent = new Intent(this, CustomCertService.class);
intent.setAction(CustomCertService.CMD_CERTIFICATION_DECISION);
intent.putExtra(CustomCertService.EXTRA_CERTIFICATE, getIntent().getSerializableExtra(EXTRA_CERTIFICATE));
intent.putExtra(CustomCertService.EXTRA_TRUSTED, trusted);
startService(intent);
}
private static String fingerprint(X509Certificate cert, String algorithm) {
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
return algorithm + ": " + hexString(md.digest(cert.getEncoded()));
} catch(NoSuchAlgorithmException|CertificateEncodingException e) {
return e.getMessage();
}
}
private static String hexString(byte[] data) {
List<String> sb = new LinkedList<>();
for (byte b : data)
sb.add(Integer.toHexString(b & 0xFF));
return TextUtils.join(":", sb);
}
}
/*
* 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 android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.CheckBox
import android.widget.TextView
import java.security.MessageDigest
import java.security.cert.CertificateParsingException
import java.security.cert.X509Certificate
import java.text.DateFormat
import java.util.*
import java.util.logging.Level
class TrustCertificateActivity: AppCompatActivity() {
companion object {
val EXTRA_CERTIFICATE = "certificate"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_trust_certificate)
showCertificate()
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
this.intent = intent
showCertificate()
}
private fun showCertificate() {
val cert = intent.getSerializableExtra(EXTRA_CERTIFICATE) as X509Certificate
val subject: String
try {
if (cert.issuerAlternativeNames != null) {
val sb = StringBuilder()
for (altName in cert.subjectAlternativeNames) {
val name = altName[1]
if (name is String)
sb.append("[").append(altName[0]).append("]").append(name).append(" ")
}
subject = sb.toString()
} else
subject = cert.subjectDN.name
var tv = findViewById(R.id.issuedFor) as TextView
tv.text = subject
tv = findViewById(R.id.issuedBy) as TextView
tv.text = cert.issuerDN.toString()
val formatter = DateFormat.getDateInstance(DateFormat.LONG)
tv = findViewById(R.id.validity_period) as TextView
tv.text = getString(R.string.trust_certificate_validity_period_value,
formatter.format(cert.notBefore),
formatter.format(cert.notAfter))
tv = findViewById(R.id.fingerprint_sha1) as TextView
tv.text = fingerprint(cert, "SHA-1")
tv = findViewById(R.id.fingerprint_sha256) as TextView
tv.text = fingerprint(cert, "SHA-256")
} catch(e: CertificateParsingException) {
Constants.log.log(Level.WARNING, "Couldn't parse certificate", e)
}
val btnAccept = findViewById(R.id.accept) as Button
val cb = findViewById(R.id.fingerprint_ok) as CheckBox
cb.setOnCheckedChangeListener { _, state -> btnAccept.isEnabled = state }
}
fun acceptCertificate(view: View) {
sendDecision(true)
finish()
}
fun rejectCertificate(view: View) {
sendDecision(false)
finish()
}
private fun sendDecision(trusted: Boolean) {
val intent = Intent(this, CustomCertService::class.java)
intent.action = CustomCertService.CMD_CERTIFICATION_DECISION
intent.putExtra(CustomCertService.EXTRA_CERTIFICATE, getIntent().getSerializableExtra(EXTRA_CERTIFICATE))
intent.putExtra(CustomCertService.EXTRA_TRUSTED, trusted)
startService(intent)
}
private fun fingerprint(cert: X509Certificate, algorithm: String): String {
try {
val md = MessageDigest.getInstance(algorithm)
return "$algorithm: ${hexString(md.digest(cert.encoded))}"
} catch(e: Exception) {
return e.message ?: "Couldn't create message digest"
}
}
private fun hexString(data: ByteArray): String {
val str = data.mapTo(LinkedList<String>()) { String.format("%02x", it) }
return TextUtils.join(":", str)
}
}
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