Invitation protocol was proceeding after confirmation timed out.

Both sides now close the connection after exchanging confirmation
results unless both results are positive.
This commit is contained in:
akwizgran
2013-05-16 15:10:16 +01:00
parent 91ccdfd8d7
commit 1692e5a695
5 changed files with 48 additions and 28 deletions

View File

@@ -288,9 +288,11 @@ implements InvitationListener {
if(code == remoteConfirmationCode) { if(code == remoteConfirmationCode) {
localMatched = true; localMatched = true;
if(remoteMatched) setView(new ContactDetailsView(this)); if(remoteMatched) setView(new ContactDetailsView(this));
else if(remoteCompared) setView(new CodesDoNotMatchView(this));
else setView(new WaitForContactView(this)); else setView(new WaitForContactView(this));
task.localConfirmationSucceeded(); task.localConfirmationSucceeded();
} else { } else {
localMatched = false;
setView(new CodesDoNotMatchView(this)); setView(new CodesDoNotMatchView(this));
task.localConfirmationFailed(); task.localConfirmationFailed();
} }
@@ -353,6 +355,7 @@ implements InvitationListener {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
remoteCompared = true; remoteCompared = true;
remoteMatched = false;
if(localMatched) if(localMatched)
setView(new CodesDoNotMatchView(AddContactActivity.this)); setView(new CodesDoNotMatchView(AddContactActivity.this));
} }

View File

@@ -106,23 +106,30 @@ class AliceConnector extends Connector {
int aliceCode = codes[0], bobCode = codes[1]; int aliceCode = codes[0], bobCode = codes[1];
group.keyAgreementSucceeded(aliceCode, bobCode); group.keyAgreementSucceeded(aliceCode, bobCode);
// Exchange confirmation results // Exchange confirmation results
boolean localMatched, remoteMatched;
try { try {
sendConfirmation(w); localMatched = group.waitForLocalConfirmationResult();
if(receiveConfirmation(r)) group.remoteConfirmationSucceeded(); sendConfirmation(w, localMatched);
else group.remoteConfirmationFailed(); remoteMatched = receiveConfirmation(r);
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true);
group.remoteConfirmationFailed(); group.remoteConfirmationFailed();
tryToClose(conn, true);
return; return;
} catch(InterruptedException e) { } catch(InterruptedException e) {
if(LOG.isLoggable(WARNING)) if(LOG.isLoggable(WARNING))
LOG.warning("Interrupted while waiting for confirmation"); LOG.warning("Interrupted while waiting for confirmation");
tryToClose(conn, true);
group.remoteConfirmationFailed(); group.remoteConfirmationFailed();
tryToClose(conn, true);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return; return;
} }
if(remoteMatched) group.remoteConfirmationSucceeded();
else group.remoteConfirmationFailed();
if(!(localMatched && remoteMatched)) {
tryToClose(conn, false);
return;
}
// The timestamp is taken after exhanging confirmation results // The timestamp is taken after exhanging confirmation results
long localTimestamp = clock.currentTimeMillis(); long localTimestamp = clock.currentTimeMillis();
// Confirmation succeeded - upgrade to a secure connection // Confirmation succeeded - upgrade to a secure connection
@@ -152,13 +159,13 @@ class AliceConnector extends Connector {
remoteProps = receiveTransportProperties(r); remoteProps = receiveTransportProperties(r);
} catch(GeneralSecurityException e) { } catch(GeneralSecurityException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true);
group.pseudonymExchangeFailed(); group.pseudonymExchangeFailed();
tryToClose(conn, true);
return; return;
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true);
group.pseudonymExchangeFailed(); group.pseudonymExchangeFailed();
tryToClose(conn, true);
return; return;
} }
// The epoch is the minimum of the peers' timestamps // The epoch is the minimum of the peers' timestamps

View File

@@ -106,23 +106,30 @@ class BobConnector extends Connector {
int aliceCode = codes[0], bobCode = codes[1]; int aliceCode = codes[0], bobCode = codes[1];
group.keyAgreementSucceeded(bobCode, aliceCode); group.keyAgreementSucceeded(bobCode, aliceCode);
// Exchange confirmation results // Exchange confirmation results
boolean localMatched, remoteMatched;
try { try {
if(receiveConfirmation(r)) group.remoteConfirmationSucceeded(); remoteMatched = receiveConfirmation(r);
else group.remoteConfirmationFailed(); localMatched = group.waitForLocalConfirmationResult();
sendConfirmation(w); sendConfirmation(w, localMatched);
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true);
group.remoteConfirmationFailed(); group.remoteConfirmationFailed();
tryToClose(conn, true);
return; return;
} catch(InterruptedException e) { } catch(InterruptedException e) {
if(LOG.isLoggable(WARNING)) if(LOG.isLoggable(WARNING))
LOG.warning("Interrupted while waiting for confirmation"); LOG.warning("Interrupted while waiting for confirmation");
tryToClose(conn, true);
group.remoteConfirmationFailed(); group.remoteConfirmationFailed();
tryToClose(conn, true);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return; return;
} }
if(remoteMatched) group.remoteConfirmationSucceeded();
else group.remoteConfirmationFailed();
if(!(localMatched && remoteMatched)) {
tryToClose(conn, false);
return;
}
// The timestamp is taken after exhanging confirmation results // The timestamp is taken after exhanging confirmation results
long localTimestamp = clock.currentTimeMillis(); long localTimestamp = clock.currentTimeMillis();
// Confirmation succeeded - upgrade to a secure connection // Confirmation succeeded - upgrade to a secure connection
@@ -152,13 +159,13 @@ class BobConnector extends Connector {
sendTransportProperties(w); sendTransportProperties(w);
} catch(GeneralSecurityException e) { } catch(GeneralSecurityException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true);
group.pseudonymExchangeFailed(); group.pseudonymExchangeFailed();
tryToClose(conn, true);
return; return;
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true);
group.pseudonymExchangeFailed(); group.pseudonymExchangeFailed();
tryToClose(conn, true);
return; return;
} }
// The epoch is the minimum of the peers' timestamps // The epoch is the minimum of the peers' timestamps

View File

@@ -175,21 +175,23 @@ abstract class Connector extends Thread {
throw new GeneralSecurityException(); throw new GeneralSecurityException();
} }
// Derive the master secret // Derive the master secret
if(LOG.isLoggable(INFO))
LOG.info(pluginName + " deriving master secret");
return crypto.deriveMasterSecret(key, keyPair, alice); return crypto.deriveMasterSecret(key, keyPair, alice);
} }
protected void sendConfirmation(Writer w) throws IOException, protected void sendConfirmation(Writer w, boolean matched)
InterruptedException { throws IOException {
boolean matched = group.waitForLocalConfirmationResult();
w.writeBoolean(matched); w.writeBoolean(matched);
w.flush(); w.flush();
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent confirmation"); if(LOG.isLoggable(INFO))
LOG.info(pluginName + " sent confirmation: " + matched);
} }
protected boolean receiveConfirmation(Reader r) throws IOException { protected boolean receiveConfirmation(Reader r) throws IOException {
boolean matched = r.readBoolean(); boolean matched = r.readBoolean();
if(LOG.isLoggable(INFO)) if(LOG.isLoggable(INFO))
LOG.info(pluginName + " received confirmation"); LOG.info(pluginName + " received confirmation: " + matched);
return matched; return matched;
} }

View File

@@ -197,15 +197,15 @@ class ConnectorGroup extends Thread implements InvitationTask {
public void localConfirmationFailed() { public void localConfirmationFailed() {
synchronized(this) { synchronized(this) {
localCompared = true; localCompared = true;
localMatched = false;
} }
localConfirmationLatch.countDown(); localConfirmationLatch.countDown();
} }
boolean getAndSetConnected() { boolean getAndSetConnected() {
boolean redundant = connected.getAndSet(true); boolean redundant = connected.getAndSet(true);
if(!redundant) { if(!redundant)
for(InvitationListener l : listeners) l.connectionSucceeded(); for(InvitationListener l : listeners) l.connectionSucceeded();
}
return redundant; return redundant;
} }
@@ -222,6 +222,13 @@ class ConnectorGroup extends Thread implements InvitationTask {
for(InvitationListener l : listeners) l.keyAgreementFailed(); for(InvitationListener l : listeners) l.keyAgreementFailed();
} }
boolean waitForLocalConfirmationResult() throws InterruptedException {
localConfirmationLatch.await(CONFIRMATION_TIMEOUT, MILLISECONDS);
synchronized(this) {
return localMatched;
}
}
void remoteConfirmationSucceeded() { void remoteConfirmationSucceeded() {
synchronized(this) { synchronized(this) {
remoteCompared = true; remoteCompared = true;
@@ -233,17 +240,11 @@ class ConnectorGroup extends Thread implements InvitationTask {
void remoteConfirmationFailed() { void remoteConfirmationFailed() {
synchronized(this) { synchronized(this) {
remoteCompared = true; remoteCompared = true;
remoteMatched = false;
} }
for(InvitationListener l : listeners) l.remoteConfirmationFailed(); for(InvitationListener l : listeners) l.remoteConfirmationFailed();
} }
boolean waitForLocalConfirmationResult() throws InterruptedException {
localConfirmationLatch.await(CONFIRMATION_TIMEOUT, MILLISECONDS);
synchronized(this) {
return localMatched;
}
}
void pseudonymExchangeSucceeded(Author remoteAuthor) { void pseudonymExchangeSucceeded(Author remoteAuthor) {
String name = remoteAuthor.getName(); String name = remoteAuthor.getName();
synchronized(this) { synchronized(this) {