aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2015-10-11 15:48:58 +0200
committerDaniel Gultsch <daniel@gultsch.de>2015-10-11 16:10:52 +0200
commit7be331bbb2ae2abde55eb031f4fdf4616846360e (patch)
treec93c08655cd8701c69429f03316af6dca4366759
parent09816b61df2fa72e7a80588982f78144fd43f173 (diff)
add menu item in account details to renew certificate
Diffstat (limited to '')
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java105
-rw-r--r--src/main/java/eu/siacs/conversations/generator/IqGenerator.java21
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java52
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java80
-rw-r--r--src/main/java/eu/siacs/conversations/utils/CryptoHelper.java19
-rw-r--r--src/main/res/menu/editaccount.xml7
-rw-r--r--src/main/res/values/strings.xml5
7 files changed, 228 insertions, 61 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 4319efb0..2c50778a 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -1,5 +1,7 @@
package eu.siacs.conversations.crypto.axolotl;
+import android.security.KeyChain;
+import android.security.KeyChainException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
@@ -18,7 +20,12 @@ import org.whispersystems.libaxolotl.state.PreKeyRecord;
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
import org.whispersystems.libaxolotl.util.KeyHelper;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -46,6 +53,7 @@ public class AxolotlService {
public static final String PEP_PREFIX = "eu.siacs.conversations.axolotl";
public static final String PEP_DEVICE_LIST = PEP_PREFIX + ".devicelist";
public static final String PEP_BUNDLES = PEP_PREFIX + ".bundles";
+ public static final String PEP_VERIFICATION = PEP_PREFIX + ".verification";
public static final String LOGPREFIX = "AxolotlService";
@@ -242,11 +250,11 @@ public class AxolotlService {
return this.pepBroken;
}
- public void regenerateKeys() {
+ public void regenerateKeys(boolean wipeOther) {
axolotlStore.regenerate();
sessions.clear();
fetchStatusMap.clear();
- publishBundlesIfNeeded(true);
+ publishBundlesIfNeeded(true, wipeOther);
}
public int getOwnDeviceId() {
@@ -380,7 +388,43 @@ public class AxolotlService {
}
}
- public void publishBundlesIfNeeded(final boolean announceAfter) {
+ public void publishDeviceVerificationAndBundle(final SignedPreKeyRecord signedPreKeyRecord,
+ final Set<PreKeyRecord> preKeyRecords,
+ final boolean announceAfter,
+ final boolean wipe) {
+ try {
+ IdentityKey axolotlPublicKey = axolotlStore.getIdentityKeyPair().getPublicKey();
+ PrivateKey x509PrivateKey = KeyChain.getPrivateKey(mXmppConnectionService, account.getPrivateKeyAlias());
+ X509Certificate[] chain = KeyChain.getCertificateChain(mXmppConnectionService, account.getPrivateKeyAlias());
+ Signature verifier = Signature.getInstance("sha256WithRSA");
+ verifier.initSign(x509PrivateKey,mXmppConnectionService.getRNG());
+ verifier.update(axolotlPublicKey.serialize());
+ byte[] signature = verifier.sign();
+ IqPacket packet = mXmppConnectionService.getIqGenerator().publishVerification(signature, chain, getOwnDeviceId());
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": publish verification for device "+getOwnDeviceId());
+ Log.d(Config.LOGTAG,"verification : "+packet.toString());
+ mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ publishDeviceBundle(signedPreKeyRecord, preKeyRecords, announceAfter, wipe);
+ }
+ });
+ } catch (KeyChainException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ Log.d(Config.LOGTAG,"no such algo "+e.getMessage());
+ e.printStackTrace();
+ } catch (java.security.InvalidKeyException e) {
+ e.printStackTrace();
+ } catch (SignatureException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ public void publishBundlesIfNeeded(final boolean announce, final boolean wipe) {
if (pepBroken) {
Log.d(Config.LOGTAG, getLogprefix(account) + "publishBundlesIfNeeded called, but PEP is broken. Ignoring... ");
return;
@@ -470,27 +514,16 @@ public class AxolotlService {
if (changed) {
- IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundles(
- signedPreKeyRecord, axolotlStore.getIdentityKeyPair().getPublicKey(),
- preKeyRecords, getOwnDeviceId());
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": Bundle " + getOwnDeviceId() + " in PEP not current. Publishing: " + publish);
- mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.RESULT) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Successfully published bundle. ");
- if (announceAfter) {
- Log.d(Config.LOGTAG, getLogprefix(account) + "Announcing device " + getOwnDeviceId());
- publishOwnDeviceIdIfNeeded();
- }
- } else {
- Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing bundle: " + packet.findChild("error"));
- }
- }
- });
+ if (account.getPrivateKeyAlias() == null) {
+ publishDeviceBundle(signedPreKeyRecord, preKeyRecords, announce, wipe);
+ } else {
+ publishDeviceVerificationAndBundle(signedPreKeyRecord, preKeyRecords, announce, wipe);
+ }
} else {
Log.d(Config.LOGTAG, getLogprefix(account) + "Bundle " + getOwnDeviceId() + " in PEP was current");
- if (announceAfter) {
+ if (wipe) {
+ wipeOtherPepDevices();
+ } else if (announce) {
Log.d(Config.LOGTAG, getLogprefix(account) + "Announcing device " + getOwnDeviceId());
publishOwnDeviceIdIfNeeded();
}
@@ -503,6 +536,32 @@ public class AxolotlService {
});
}
+ private void publishDeviceBundle(SignedPreKeyRecord signedPreKeyRecord,
+ Set<PreKeyRecord> preKeyRecords,
+ final boolean announceAfter,
+ final boolean wipe) {
+ IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundles(
+ signedPreKeyRecord, axolotlStore.getIdentityKeyPair().getPublicKey(),
+ preKeyRecords, getOwnDeviceId());
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": Bundle " + getOwnDeviceId() + " in PEP not current. Publishing: " + publish);
+ mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Successfully published bundle. ");
+ if (wipe) {
+ wipeOtherPepDevices();
+ } else if (announceAfter) {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Announcing device " + getOwnDeviceId());
+ publishOwnDeviceIdIfNeeded();
+ }
+ } else {
+ Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing bundle: " + packet.findChild("error"));
+ }
+ }
+ });
+ }
+
public boolean isContactAxolotlCapable(Contact contact) {
Jid jid = contact.getJid().toBareJid();
return hasAny(contact) ||
@@ -774,7 +833,7 @@ public class AxolotlService {
plaintextMessage = message.decrypt(session, getOwnDeviceId());
Integer preKeyId = session.getPreKeyId();
if (preKeyId != null) {
- publishBundlesIfNeeded(false);
+ publishBundlesIfNeeded(false, false);
session.resetPreKeyId();
}
} catch (CryptoFailedException e) {
diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
index ba852606..fb69860d 100644
--- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
@@ -2,16 +2,20 @@ package eu.siacs.conversations.generator;
import android.util.Base64;
+import android.util.Log;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.libaxolotl.state.PreKeyRecord;
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
@@ -173,6 +177,23 @@ public class IqGenerator extends AbstractGenerator {
return publish(AxolotlService.PEP_BUNDLES+":"+deviceId, item);
}
+ public IqPacket publishVerification(byte[] signature, X509Certificate[] certificates, final int deviceId) {
+ final Element item = new Element("item");
+ final Element verification = item.addChild("verification", AxolotlService.PEP_PREFIX);
+ final Element chain = verification.addChild("chain");
+ for(int i = 0; i < certificates.length; ++i) {
+ try {
+ Element certificate = chain.addChild("certificate");
+ certificate.setContent(Base64.encodeToString(certificates[i].getEncoded(), Base64.DEFAULT));
+ certificate.setAttribute("index",i);
+ } catch (CertificateEncodingException e) {
+ Log.d(Config.LOGTAG, "could not encode certificate");
+ }
+ }
+ verification.addChild("signature").setContent(Base64.encodeToString(signature, Base64.DEFAULT));
+ return publish(AxolotlService.PEP_VERIFICATION+":"+deviceId, item);
+ }
+
public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) {
final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
final Element query = packet.query("urn:xmpp:mam:0");
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 9938c18f..f3bd545a 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -30,6 +30,7 @@ import android.security.KeyChainException;
import android.util.Log;
import android.util.LruCache;
import android.util.DisplayMetrics;
+import android.util.Pair;
import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session;
@@ -37,21 +38,17 @@ import net.java.otr4j.session.SessionID;
import net.java.otr4j.session.SessionImpl;
import net.java.otr4j.session.SessionStatus;
-import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x500.style.IETFUtils;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
-import org.bouncycastle.jce.PrincipalUtil;
-import org.bouncycastle.jce.X509Principal;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
import java.math.BigInteger;
-import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateParsingException;
+import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
@@ -175,7 +172,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
mMessageArchiveService.executePendingQueries(account);
mJingleConnectionManager.cancelInTransmission();
syncDirtyContacts(account);
- account.getAxolotlService().publishBundlesIfNeeded(true);
+ account.getAxolotlService().publishBundlesIfNeeded(true, false);
}
};
private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
@@ -1307,17 +1304,18 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void run() {
try {
X509Certificate[] chain = KeyChain.getCertificateChain(XmppConnectionService.this, alias);
- PrivateKey key = KeyChain.getPrivateKey(XmppConnectionService.this, alias);
- X500Name x500name = new JcaX509CertificateHolder(chain[0]).getSubject();
- String email = IETFUtils.valueToString(x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue());
- String name = IETFUtils.valueToString(x500name.getRDNs(BCStyle.CN)[0].getFirst().getValue());
- Jid jid = Jid.fromString(email);
- if (findAccountByJid(jid) == null) {
- Account account = new Account(jid, "");
+ Pair<Jid,String> info = CryptoHelper.extractJidAndName(chain[0]);
+ if (findAccountByJid(info.first) == null) {
+ Account account = new Account(info.first, "");
account.setPrivateKeyAlias(alias);
account.setOption(Account.OPTION_DISABLED, true);
createAccount(account);
callback.onAccountCreated(account);
+ try {
+ getMemorizingTrustManager().getNonInteractive().checkClientTrusted(chain, "RSA");
+ } catch (CertificateException e) {
+ callback.informUser(R.string.certificate_chain_is_not_trusted);
+ }
} else {
callback.informUser(R.string.account_already_exists);
}
@@ -1338,6 +1336,34 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
+ public void updateKeyInAccount(final Account account, final String alias) {
+ Log.d(Config.LOGTAG,"update key in account "+alias);
+ try {
+ X509Certificate[] chain = KeyChain.getCertificateChain(XmppConnectionService.this, alias);
+ Pair<Jid, String> info = CryptoHelper.extractJidAndName(chain[0]);
+ if (account.getJid().toBareJid().equals(info.first)) {
+ account.setPrivateKeyAlias(alias);
+ databaseBackend.updateAccount(account);
+ try {
+ getMemorizingTrustManager().getNonInteractive().checkClientTrusted(chain, "RSA");
+ } catch (CertificateException e) {
+ showErrorToastInUi(R.string.certificate_chain_is_not_trusted);
+ }
+ account.getAxolotlService().regenerateKeys(true);
+ } else {
+ showErrorToastInUi(R.string.jid_does_not_match_certificate);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (KeyChainException e) {
+ e.printStackTrace();
+ } catch (InvalidJidException e) {
+ e.printStackTrace();
+ } catch (CertificateEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
public void updateAccount(final Account account) {
this.statusListener.onStatusChanged(account);
databaseBackend.updateAccount(account);
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index cba9275f..faafc24a 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -7,6 +7,8 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
@@ -34,6 +36,7 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested;
+import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.utils.CryptoHelper;
@@ -46,7 +49,7 @@ import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.pep.Avatar;
public class EditAccountActivity extends XmppActivity implements OnAccountUpdate,
- OnKeyStatusUpdated, OnCaptchaRequested {
+ OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast {
private AutoCompleteTextView mAccountJid;
private EditText mPassword;
@@ -107,7 +110,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
final Jid jid;
try {
if (Config.DOMAIN_LOCK != null) {
- jid = Jid.fromParts(mAccountJid.getText().toString(),Config.DOMAIN_LOCK,null);
+ jid = Jid.fromParts(mAccountJid.getText().toString(), Config.DOMAIN_LOCK, null);
} else {
jid = Jid.fromString(mAccountJid.getText().toString());
}
@@ -182,7 +185,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
&& mAccount.getStatus() != Account.State.ONLINE
&& mFetchingAvatar) {
startActivity(new Intent(getApplicationContext(),
- ManageAccountActivity.class));
+ ManageAccountActivity.class));
finish();
} else if (mInitMode && mAccount != null && mAccount.getStatus() == Account.State.ONLINE) {
if (!mFetchingAvatar) {
@@ -201,6 +204,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
public void onAccountUpdate() {
refreshUi();
}
+
private final UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
@Override
@@ -318,7 +322,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
@Override
protected String getShareableUri() {
- if (mAccount!=null) {
+ if (mAccount != null) {
return mAccount.getShareableUri();
} else {
return "";
@@ -369,7 +373,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
final OnCheckedChangeListener OnCheckedShowConfirmPassword = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton buttonView,
- final boolean isChecked) {
+ final boolean isChecked) {
if (isChecked) {
mPasswordConfirm.setVisibility(View.VISIBLE);
} else {
@@ -393,6 +397,10 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
final MenuItem showMoreInfo = menu.findItem(R.id.action_server_info_show_more);
final MenuItem changePassword = menu.findItem(R.id.action_change_password_on_server);
final MenuItem clearDevices = menu.findItem(R.id.action_clear_devices);
+ final MenuItem renewCertificate = menu.findItem(R.id.action_renew_certificate);
+
+ renewCertificate.setVisible(mAccount != null && mAccount.getPrivateKeyAlias() != null);
+
if (mAccount != null && mAccount.isOnlineAndConnected()) {
if (!mAccount.getXmppConnection().getFeatures().blocking()) {
showBlocklist.setVisible(false);
@@ -445,11 +453,12 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
this.mAccount = xmppConnectionService.findAccountByJid(jidToEdit);
if (this.mAccount != null) {
if (this.mAccount.getPrivateKeyAlias() != null) {
- this.mPassword.setHint(R.string.authenticate_with_certificate);
- if (this.mInitMode) {
- this.mPassword.requestFocus();
+ this.mPassword.setHint(R.string.authenticate_with_certificate);
+ if (this.mInitMode) {
+ this.mPassword.requestFocus();
+ }
}
- } updateAccountInformation(true);
+ updateAccountInformation(true);
}
} else if (this.xmppConnectionService.getAccounts().size() == 0) {
if (getActionBar() != null) {
@@ -489,10 +498,24 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
case R.id.action_clear_devices:
showWipePepDialog();
break;
+ case R.id.action_renew_certificate:
+ renewCertificate();
+ break;
}
return super.onOptionsItemSelected(item);
}
+ private void renewCertificate() {
+ KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
+ }
+
+ @Override
+ public void alias(String alias) {
+ if (alias != null) {
+ xmppConnectionService.updateKeyInAccount(mAccount, alias);
+ }
+ }
+
private void updateAccountInformation(boolean init) {
if (init) {
if (Config.DOMAIN_LOCK != null) {
@@ -517,7 +540,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
if (this.mAccount.isOnlineAndConnected() && !this.mFetchingAvatar) {
this.mStats.setVisibility(View.VISIBLE);
this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(this, this.mAccount.getXmppConnection()
- .getLastSessionEstablished()));
+ .getLastSessionEstablished()));
Features features = this.mAccount.getXmppConnection().getFeatures();
if (features.rosterVersioning()) {
this.mServerInfoRosterVersion.setText(R.string.server_info_available);
@@ -528,7 +551,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
this.mServerInfoCarbons.setText(R.string.server_info_available);
} else {
this.mServerInfoCarbons
- .setText(R.string.server_info_unavailable);
+ .setText(R.string.server_info_unavailable);
}
if (features.mam()) {
this.mServerInfoMam.setText(R.string.server_info_available);
@@ -570,21 +593,21 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
this.mOtrFingerprintBox.setVisibility(View.VISIBLE);
this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(otrFingerprint));
this.mOtrFingerprintToClipboardButton
- .setVisibility(View.VISIBLE);
+ .setVisibility(View.VISIBLE);
this.mOtrFingerprintToClipboardButton
- .setOnClickListener(new View.OnClickListener() {
+ .setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(final View v) {
+ @Override
+ public void onClick(final View v) {
- if (copyTextToClipboard(otrFingerprint, R.string.otr_fingerprint)) {
- Toast.makeText(
- EditAccountActivity.this,
- R.string.toast_message_otr_fingerprint,
- Toast.LENGTH_SHORT).show();
+ if (copyTextToClipboard(otrFingerprint, R.string.otr_fingerprint)) {
+ Toast.makeText(
+ EditAccountActivity.this,
+ R.string.toast_message_otr_fingerprint,
+ Toast.LENGTH_SHORT).show();
+ }
}
- }
- });
+ });
} else {
this.mOtrFingerprintBox.setVisibility(View.GONE);
}
@@ -627,7 +650,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
boolean hasKeys = false;
keys.removeAllViews();
for (final String fingerprint : mAccount.getAxolotlService().getFingerprintsForOwnSessions()) {
- if(ownFingerprint.equals(fingerprint)) {
+ if (ownFingerprint.equals(fingerprint)) {
continue;
}
boolean highlight = fingerprint.equals(messageFingerprint);
@@ -661,7 +684,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mAccount.getAxolotlService().regenerateKeys();
+ mAccount.getAxolotlService().regenerateKeys(false);
}
});
builder.create().show();
@@ -753,4 +776,13 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
}
});
}
+
+ public void onShowErrorToast(final int resId) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(EditAccountActivity.this, resId, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
index c7c9ac42..e9ad7197 100644
--- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
@@ -1,6 +1,15 @@
package eu.siacs.conversations.utils;
+import android.util.Pair;
+
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x500.style.IETFUtils;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+
import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
import java.text.Normalizer;
import java.util.Arrays;
import java.util.Collection;
@@ -9,6 +18,8 @@ import java.util.LinkedHashSet;
import java.util.List;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.jid.Jid;
public final class CryptoHelper {
public static final String FILETRANSFER = "?FILETRANSFERv1:";
@@ -125,4 +136,12 @@ public final class CryptoHelper {
}
}
}
+
+ public static Pair<Jid,String> extractJidAndName(X509Certificate certificate) throws CertificateEncodingException, InvalidJidException {
+ X500Name x500name = new JcaX509CertificateHolder(certificate).getSubject();
+ //String xmpp = IETFUtils.valueToString(x500name.getRDNs(new ASN1ObjectIdentifier("1.3.6.1.5.5.7.8.5"))[0].getFirst().getValue());
+ String email = IETFUtils.valueToString(x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue());
+ String name = IETFUtils.valueToString(x500name.getRDNs(BCStyle.CN)[0].getFirst().getValue());
+ return new Pair<>(Jid.fromString(email),name);
+ }
}
diff --git a/src/main/res/menu/editaccount.xml b/src/main/res/menu/editaccount.xml
index 2076805e..62981a45 100644
--- a/src/main/res/menu/editaccount.xml
+++ b/src/main/res/menu/editaccount.xml
@@ -11,6 +11,13 @@
android:showAsAction="never" />
<item
+ android:id="@+id/action_renew_certificate"
+ android:title="@string/action_renew_certificate"
+ android:visible="false"
+ android:showAsAction="never" />
+ />
+
+ <item
android:id="@+id/action_server_info_show_more"
android:title="@string/server_info_show_more"
android:checkable="true"
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 3307b973..20b861f4 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -524,10 +524,13 @@
<string name="pref_away_when_screen_off_summary">Marks your resource as away when the screen is turned off</string>
<string name="pref_xa_on_silent_mode">Not available in silent mode</string>
<string name="pref_xa_on_silent_mode_summary">Marks your resource as not available when phone is in silent mode</string>
- <string name="action_add_account_from_key">Add account from key</string>
+ <string name="action_add_account_from_key">Add account from certificate</string>
<string name="unable_to_parse_certificate">Unable to parse certificate</string>
<string name="authenticate_with_certificate">Leave empty to authenticate w/ certificate</string>
<string name="captcha_ocr">Captcha text</string>
<string name="captcha_required">Captcha required</string>
<string name="captcha_hint">enter the text from the image</string>
+ <string name="certificate_chain_is_not_trusted">Certificate chain is not trusted</string>
+ <string name="jid_does_not_match_certificate">Jabber ID does not match certificate</string>
+ <string name="action_renew_certificate">Renew certificate</string>
</resources>