aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2015-12-23 19:18:53 +0100
committerDaniel Gultsch <daniel@gultsch.de>2015-12-23 19:18:53 +0100
commitf46cbb38a92ff5281a974ecc0932ba5459c7334e (patch)
treebe812812e040602398584ab65764203326bd19e3 /src/main/java/eu/siacs
parentd0bad09f13886c7d8ee20c0205293cb0250d9c2f (diff)
show certificate information
Diffstat (limited to 'src/main/java/eu/siacs')
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java4
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java4
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java39
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java44
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java10
-rw-r--r--src/main/java/eu/siacs/conversations/utils/CryptoHelper.java50
8 files changed, 145 insertions, 10 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
index ad9b8be3..31b23e3c 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -575,6 +575,10 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
return axolotlStore.getFingerprintTrust(fingerprint);
}
+ public X509Certificate getFingerprintCertificate(String fingerprint) {
+ return axolotlStore.getFingerprintCertificate(fingerprint);
+ }
+
public void setFingerprintTrust(String fingerprint, XmppAxolotlSession.Trust trust) {
axolotlStore.setFingerprintTrust(fingerprint, trust);
}
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java
index 788a391d..3c8cb3c1 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java
@@ -219,6 +219,10 @@ public class SQLiteAxolotlStore implements AxolotlStore {
mXmppConnectionService.databaseBackend.setIdentityKeyCertificate(account, fingerprint, x509Certificate);
}
+ public X509Certificate getFingerprintCertificate(String fingerprint) {
+ return mXmppConnectionService.databaseBackend.getIdentityKeyCertifcate(account, fingerprint);
+ }
+
public Set<IdentityKey> getContactKeysWithTrust(String bareJid, XmppAxolotlSession.Trust trust) {
return mXmppConnectionService.databaseBackend.loadIdentityKeys(account, bareJid, trust);
}
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index 4882d72b..3077c488 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -15,13 +15,15 @@ import org.whispersystems.libaxolotl.AxolotlAddress;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.libaxolotl.InvalidKeyException;
-import org.whispersystems.libaxolotl.state.AxolotlStore;
import org.whispersystems.libaxolotl.state.PreKeyRecord;
import org.whispersystems.libaxolotl.state.SessionRecord;
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;
@@ -600,16 +602,16 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.delete(Message.TABLENAME, Message.CONVERSATION + "=?", args);
}
- public Pair<Long,String> getLastMessageReceived(Account account) {
+ public Pair<Long, String> getLastMessageReceived(Account account) {
SQLiteDatabase db = this.getReadableDatabase();
String sql = "select messages.timeSent,messages.serverMsgId from accounts join conversations on accounts.uuid=conversations.accountUuid join messages on conversations.uuid=messages.conversationUuid where accounts.uuid=? and (messages.status=0 or messages.carbon=1 or messages.serverMsgId not null) order by messages.timesent desc limit 1";
String[] args = {account.getUuid()};
Cursor cursor = db.rawQuery(sql, args);
- if (cursor.getCount() ==0) {
+ if (cursor.getCount() == 0) {
return null;
} else {
cursor.moveToFirst();
- return new Pair<>(cursor.getLong(0),cursor.getString(1));
+ return new Pair<>(cursor.getLong(0), cursor.getString(1));
}
}
@@ -1072,11 +1074,38 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ SQLiteAxolotlStore.FINGERPRINT + " = ? ",
selectionArgs) == 1;
} catch (CertificateEncodingException e) {
- Log.d(Config.LOGTAG,"could not encode certificate");
+ Log.d(Config.LOGTAG, "could not encode certificate");
return false;
}
}
+ public X509Certificate getIdentityKeyCertifcate(Account account, String fingerprint) {
+ SQLiteDatabase db = this.getReadableDatabase();
+ String[] selectionArgs = {
+ account.getUuid(),
+ fingerprint
+ };
+ String[] colums = {SQLiteAxolotlStore.CERTIFICATE};
+ String selection = SQLiteAxolotlStore.ACCOUNT + " = ? AND " + SQLiteAxolotlStore.FINGERPRINT + " = ? ";
+ Cursor cursor = db.query(SQLiteAxolotlStore.IDENTITIES_TABLENAME, colums, selection, selectionArgs, null, null, null);
+ if (cursor.getCount() < 1) {
+ return null;
+ } else {
+ cursor.moveToFirst();
+ byte[] certificate = cursor.getBlob(cursor.getColumnIndex(SQLiteAxolotlStore.CERTIFICATE));
+ if (certificate == null || certificate.length == 0) {
+ return null;
+ }
+ try {
+ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+ return (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certificate));
+ } catch (CertificateException e) {
+ Log.d(Config.LOGTAG,"certificate exception "+e.getMessage());
+ return null;
+ }
+ }
+ }
+
public void storeIdentityKey(Account account, String name, IdentityKey identityKey) {
storeIdentityKey(account, name, false, identityKey.getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 10bdaab1..5143190f 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -14,6 +14,7 @@ import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -30,12 +31,14 @@ import android.widget.TextView;
import org.openintents.openpgp.util.OpenPgpUtils;
+import java.security.cert.X509Certificate;
import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
+import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.ListItem;
@@ -394,7 +397,12 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
}
for (final String fingerprint : contact.getAccount().getAxolotlService().getFingerprintsForContact(contact)) {
boolean highlight = fingerprint.equals(messageFingerprint);
- hasKeys |= addFingerprintRow(keys, contact.getAccount(), fingerprint, highlight);
+ hasKeys |= addFingerprintRow(keys, contact.getAccount(), fingerprint, highlight, new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onOmemoKeyClicked(contact.getAccount(), fingerprint);
+ }
+ });
}
if (contact.getPgpKeyId() != 0) {
hasKeys = true;
@@ -446,6 +454,40 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
}
}
+ private void onOmemoKeyClicked(Account account, String fingerprint) {
+ Log.d(Config.LOGTAG,"on omemo key clicked");
+ final XmppAxolotlSession.Trust trust = account.getAxolotlService().getFingerprintTrust(fingerprint);
+ if (trust != null) {
+ X509Certificate x509Certificate = account.getAxolotlService().getFingerprintCertificate(fingerprint);
+ if (x509Certificate != null) {
+ Log.d(Config.LOGTAG, "certificate for fingerprint " + fingerprint + " was not null");
+ showCertificateInformationDialog(CryptoHelper.extractCertificateInformation(x509Certificate));
+ }
+ }
+ }
+
+ private void showCertificateInformationDialog(Bundle bundle) {
+ View view = getLayoutInflater().inflate(R.layout.certificate_information, null);
+ final String not_available = getString(R.string.certicate_info_not_available);
+ TextView subject_cn = (TextView) view.findViewById(R.id.subject_cn);
+ TextView subject_o = (TextView) view.findViewById(R.id.subject_o);
+ TextView issuer_cn = (TextView) view.findViewById(R.id.issuer_cn);
+ TextView issuer_o = (TextView) view.findViewById(R.id.issuer_o);
+ TextView sha1 = (TextView) view.findViewById(R.id.sha1);
+
+ subject_cn.setText(bundle.getString("subject_cn", not_available));
+ subject_o.setText(bundle.getString("subject_o", not_available));
+ issuer_cn.setText(bundle.getString("issuer_cn", not_available));
+ issuer_o.setText(bundle.getString("issuer_o", not_available));
+ sha1.setText(bundle.getString("sha1", not_available));
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.certificate_information);
+ builder.setView(view);
+ builder.setPositiveButton(R.string.ok, null);
+ builder.create().show();
+ }
+
protected void confirmToDeleteFingerprint(final String fingerprint) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.delete_fingerprint);
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index a6c45996..31d26b23 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -710,7 +710,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
continue;
}
boolean highlight = fingerprint.equals(messageFingerprint);
- hasKeys |= addFingerprintRow(keys, mAccount, fingerprint, highlight);
+ hasKeys |= addFingerprintRow(keys, mAccount, fingerprint, highlight, null);
}
if (hasKeys) {
keysCard.setVisibility(View.VISIBLE);
diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
index 4bd0d42d..2e6d3246 100644
--- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
@@ -126,6 +126,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
// own fingerprints have no impact on locked status.
}
},
+ null,
null
);
}
@@ -140,6 +141,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
lockOrUnlockAsNeeded();
}
},
+ null,
null
);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 4cb93fde..b372692d 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -648,7 +648,7 @@ public abstract class XmppActivity extends Activity {
builder.create().show();
}
- protected boolean addFingerprintRow(LinearLayout keys, final Account account, final String fingerprint, boolean highlight) {
+ protected boolean addFingerprintRow(LinearLayout keys, final Account account, final String fingerprint, boolean highlight, View.OnClickListener onKeyClickedListener) {
final XmppAxolotlSession.Trust trust = account.getAxolotlService()
.getFingerprintTrust(fingerprint);
if (trust == null) {
@@ -670,7 +670,8 @@ public abstract class XmppActivity extends Activity {
XmppAxolotlSession.Trust.UNTRUSTED);
v.setEnabled(true);
}
- }
+ },
+ onKeyClickedListener
);
}
@@ -682,13 +683,16 @@ public abstract class XmppActivity extends Activity {
boolean showTag,
CompoundButton.OnCheckedChangeListener
onCheckedChangeListener,
- View.OnClickListener onClickListener) {
+ View.OnClickListener onClickListener,
+ View.OnClickListener onKeyClickedListener) {
if (trust == XmppAxolotlSession.Trust.COMPROMISED) {
return false;
}
View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false);
TextView key = (TextView) view.findViewById(R.id.key);
+ key.setOnClickListener(onKeyClickedListener);
TextView keyType = (TextView) view.findViewById(R.id.key_type);
+ keyType.setOnClickListener(onKeyClickedListener);
Switch trustToggle = (Switch) view.findViewById(R.id.tgl_trust);
trustToggle.setVisibility(View.VISIBLE);
trustToggle.setOnCheckedChangeListener(onCheckedChangeListener);
diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
index ab407249..d1b90ab6 100644
--- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.utils;
+import android.os.Bundle;
import android.util.Log;
import android.util.Pair;
@@ -9,6 +10,7 @@ import org.bouncycastle.asn1.x500.style.IETFUtils;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.jce.PrincipalUtil;
+import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateParsingException;
@@ -121,6 +123,14 @@ public final class CryptoHelper {
return builder.toString();
}
+ public static String prettifyFingerprintCert(String fingerprint) {
+ StringBuilder builder = new StringBuilder(fingerprint);
+ for(int i=2;i < builder.length(); i+=3) {
+ builder.insert(i,':');
+ }
+ return builder.toString();
+ }
+
public static String[] getOrderedCipherSuites(final String[] platformSupportedCipherSuites) {
final Collection<String> cipherSuites = new LinkedHashSet<>(Arrays.asList(Config.ENABLED_CIPHERS));
final List<String> platformCiphers = Arrays.asList(platformSupportedCipherSuites);
@@ -167,6 +177,46 @@ public final class CryptoHelper {
}
}
+ public static Bundle extractCertificateInformation(X509Certificate certificate) {
+ Bundle information = new Bundle();
+ try {
+ JcaX509CertificateHolder holder = new JcaX509CertificateHolder(certificate);
+ X500Name subject = holder.getSubject();
+ try {
+ information.putString("subject_cn", subject.getRDNs(BCStyle.CN)[0].getFirst().getValue().toString());
+ } catch (Exception e) {
+ //ignored
+ }
+ try {
+ information.putString("subject_o",subject.getRDNs(BCStyle.O)[0].getFirst().getValue().toString());
+ } catch (Exception e) {
+ //ignored
+ }
+
+ X500Name issuer = holder.getIssuer();
+ try {
+ information.putString("issuer_cn", issuer.getRDNs(BCStyle.CN)[0].getFirst().getValue().toString());
+ } catch (Exception e) {
+ //ignored
+ }
+ try {
+ information.putString("issuer_o", issuer.getRDNs(BCStyle.O)[0].getFirst().getValue().toString());
+ } catch (Exception e) {
+ //ignored
+ }
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] fingerprint = md.digest(certificate.getEncoded());
+ information.putString("sha1", prettifyFingerprintCert(bytesToHex(fingerprint)));
+ } catch (Exception e) {
+
+ }
+ return information;
+ } catch (CertificateEncodingException e) {
+ return information;
+ }
+ }
+
public static int encryptionTypeToText(int encryption) {
switch (encryption) {
case Message.ENCRYPTION_OTR: