synchronize access to json key storage in account model
This commit is contained in:
parent
501152bcfd
commit
f6cfa27741
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in a new issue