synchronize access to json key storage in account model

This commit is contained in:
Daniel Gultsch 2016-10-13 11:27:26 +02:00
parent 501152bcfd
commit f6cfa27741
3 changed files with 75 additions and 73 deletions

View file

@ -53,28 +53,30 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
this.mXmppConnectionService = service; this.mXmppConnectionService = service;
} }
private KeyPair loadKey(JSONObject keys) { private KeyPair loadKey(final JSONObject keys) {
if (keys == null) { if (keys == null) {
return null; return null;
} }
try { synchronized (keys) {
BigInteger x = new BigInteger(keys.getString("otr_x"), 16); try {
BigInteger y = new BigInteger(keys.getString("otr_y"), 16); BigInteger x = new BigInteger(keys.getString("otr_x"), 16);
BigInteger p = new BigInteger(keys.getString("otr_p"), 16); BigInteger y = new BigInteger(keys.getString("otr_y"), 16);
BigInteger q = new BigInteger(keys.getString("otr_q"), 16); BigInteger p = new BigInteger(keys.getString("otr_p"), 16);
BigInteger g = new BigInteger(keys.getString("otr_g"), 16); BigInteger q = new BigInteger(keys.getString("otr_q"), 16);
KeyFactory keyFactory = KeyFactory.getInstance("DSA"); BigInteger g = new BigInteger(keys.getString("otr_g"), 16);
DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(y, p, q, g); KeyFactory keyFactory = KeyFactory.getInstance("DSA");
DSAPrivateKeySpec privateKeySpec = new DSAPrivateKeySpec(x, p, q, g); DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(y, p, q, g);
PublicKey publicKey = keyFactory.generatePublic(pubKeySpec); DSAPrivateKeySpec privateKeySpec = new DSAPrivateKeySpec(x, p, q, g);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec); PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
return new KeyPair(publicKey, privateKey); PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
} catch (JSONException e) { return new KeyPair(publicKey, privateKey);
return null; } catch (JSONException e) {
} catch (NoSuchAlgorithmException e) { return null;
return null; } catch (NoSuchAlgorithmException e) {
} catch (InvalidKeySpecException e) { return null;
return null; } catch (InvalidKeySpecException e) {
return null;
}
} }
} }

View file

@ -203,7 +203,7 @@ public class Account extends AbstractEntity {
protected int options = 0; protected int options = 0;
protected String rosterVersion; protected String rosterVersion;
protected State status = State.OFFLINE; protected State status = State.OFFLINE;
protected JSONObject keys = new JSONObject(); protected final JSONObject keys;
protected String avatar; protected String avatar;
protected String displayName = null; protected String displayName = null;
protected String hostname = null; protected String hostname = null;
@ -238,11 +238,13 @@ public class Account extends AbstractEntity {
this.password = password; this.password = password;
this.options = options; this.options = options;
this.rosterVersion = rosterVersion; this.rosterVersion = rosterVersion;
JSONObject tmp;
try { try {
this.keys = new JSONObject(keys); tmp = new JSONObject(keys);
} catch (final JSONException ignored) { } catch(JSONException e) {
this.keys = new JSONObject(); tmp = new JSONObject();
} }
this.keys = tmp;
this.avatar = avatar; this.avatar = avatar;
this.displayName = displayName; this.displayName = displayName;
this.hostname = hostname; this.hostname = hostname;
@ -391,15 +393,28 @@ public class Account extends AbstractEntity {
} }
public String getKey(final String name) { public String getKey(final String name) {
return this.keys.optString(name, null); synchronized (this.keys) {
return this.keys.optString(name, null);
}
}
public int getKeyAsInt(final String name, int defaultValue) {
String key = getKey(name);
try {
return key == null ? defaultValue : Integer.parseInt(key);
} catch (NumberFormatException e) {
return defaultValue;
}
} }
public boolean setKey(final String keyName, final String keyValue) { public boolean setKey(final String keyName, final String keyValue) {
try { synchronized (this.keys) {
this.keys.put(keyName, keyValue); try {
return true; this.keys.put(keyName, keyValue);
} catch (final JSONException e) { return true;
return false; } catch (final JSONException e) {
return false;
}
} }
} }
@ -419,7 +434,9 @@ public class Account extends AbstractEntity {
values.put(SERVER, jid.getDomainpart()); values.put(SERVER, jid.getDomainpart());
values.put(PASSWORD, password); values.put(PASSWORD, password);
values.put(OPTIONS, options); values.put(OPTIONS, options);
values.put(KEYS, this.keys.toString()); synchronized (this.keys) {
values.put(KEYS, this.keys.toString());
}
values.put(ROSTERVERSION, rosterVersion); values.put(ROSTERVERSION, rosterVersion);
values.put(AVATAR, avatar); values.put(AVATAR, avatar);
values.put(DISPLAY_NAME, displayName); values.put(DISPLAY_NAME, displayName);
@ -496,54 +513,42 @@ public class Account extends AbstractEntity {
} }
public String getPgpSignature() { public String getPgpSignature() {
try { return getKey(KEY_PGP_SIGNATURE);
if (keys.has(KEY_PGP_SIGNATURE) && !"null".equals(keys.getString(KEY_PGP_SIGNATURE))) {
return keys.getString(KEY_PGP_SIGNATURE);
} else {
return null;
}
} catch (final JSONException e) {
return null;
}
} }
public boolean setPgpSignature(String signature) { public boolean setPgpSignature(String signature) {
try { return setKey(KEY_PGP_SIGNATURE, signature);
keys.put(KEY_PGP_SIGNATURE, signature);
} catch (JSONException e) {
return false;
}
return true;
} }
public boolean unsetPgpSignature() { public boolean unsetPgpSignature() {
try { synchronized (this.keys) {
keys.put(KEY_PGP_SIGNATURE, JSONObject.NULL); return keys.remove(KEY_PGP_SIGNATURE) != null;
} catch (JSONException e) {
return false;
} }
return true;
} }
public long getPgpId() { public long getPgpId() {
if (keys.has(KEY_PGP_ID)) { synchronized (this.keys) {
try { if (keys.has(KEY_PGP_ID)) {
return keys.getLong(KEY_PGP_ID); try {
} catch (JSONException e) { return keys.getLong(KEY_PGP_ID);
} catch (JSONException e) {
return 0;
}
} else {
return 0; return 0;
} }
} else {
return 0;
} }
} }
public boolean setPgpSignId(long pgpID) { public boolean setPgpSignId(long pgpID) {
try { synchronized (this.keys) {
keys.put(KEY_PGP_ID, pgpID); try {
} catch (JSONException e) { keys.put(KEY_PGP_ID, pgpID);
return false; } catch (JSONException e) {
return false;
}
return true;
} }
return true;
} }
public Roster getRoster() { public Roster getRoster() {

View file

@ -852,18 +852,13 @@ public class XmppConnection implements Runnable {
saslMechanism = new Anonymous(tagWriter, account, mXmppConnectionService.getRNG()); saslMechanism = new Anonymous(tagWriter, account, mXmppConnectionService.getRNG());
} }
if (saslMechanism != null) { if (saslMechanism != null) {
final JSONObject keys = account.getKeys(); final int pinnedMechanism = account.getKeyAsInt(Account.PINNED_MECHANISM_KEY, -1);
try { if (pinnedMechanism > saslMechanism.getPriority()) {
if (keys.has(Account.PINNED_MECHANISM_KEY) && Log.e(Config.LOGTAG, "Auth failed. Authentication mechanism " + saslMechanism.getMechanism() +
keys.getInt(Account.PINNED_MECHANISM_KEY) > saslMechanism.getPriority()) { " has lower priority (" + String.valueOf(saslMechanism.getPriority()) +
Log.e(Config.LOGTAG, "Auth failed. Authentication mechanism " + saslMechanism.getMechanism() + ") than pinned priority (" + pinnedMechanism +
" has lower priority (" + String.valueOf(saslMechanism.getPriority()) + "). Possible downgrade attack?");
") than pinned priority (" + keys.getInt(Account.PINNED_MECHANISM_KEY) + throw new SecurityException();
"). Possible downgrade attack?");
throw new SecurityException();
}
} catch (final JSONException e) {
Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism");
} }
Log.d(Config.LOGTAG, account.getJid().toString() + ": Authenticating with " + saslMechanism.getMechanism()); Log.d(Config.LOGTAG, account.getJid().toString() + ": Authenticating with " + saslMechanism.getMechanism());
auth.setAttribute("mechanism", saslMechanism.getMechanism()); auth.setAttribute("mechanism", saslMechanism.getMechanism());