Make get_verifier() wait for _confirm to arrive
This improves the error behavior when --verify is used but there's a WrongPasswordError: the mismatch is detected before the verifiers are displayed or confirmation is requested. It requires that the far end sends a "_confirm" message, which was introduced in release 0.6.0. Use with older versions (if it doesn't break for other reasons) will cause a hang. This patch also deletes test_twisted.Basic.test_verifier_mismatch, since both sides now detect this on their own. It changes test_wrong_password() too, since we might now notice the error during send_data (previously we'd only see it in get_data).
This commit is contained in:
parent
c017de5e4b
commit
b70c2f8868
|
@ -109,11 +109,20 @@ class Basic(ServerBase, unittest.TestCase):
|
|||
# * w2 will send w2.PAKE, wait for (and get) w1.PAKE, compute a key,
|
||||
# send w2.CONFIRM, then wait for w1.DATA.
|
||||
# * w1 will get w2.PAKE, compute a key, send w1.CONFIRM.
|
||||
# * w1 might also get w2.CONFIRM, and may notice the error before it
|
||||
# sends w1.CONFIRM, in which case the wait=True will signal an
|
||||
# error inside _get_master_key() (inside send_data), and d1 will
|
||||
# errback.
|
||||
# * but w1 might not see w2.CONFIRM yet, in which case it won't
|
||||
# errback until we do w1.get_data()
|
||||
# * w2 gets w1.CONFIRM, notices the error, records it.
|
||||
# * w2 (waiting for w1.DATA) wakes up, sees the error, throws
|
||||
# * meanwhile w1 finishes sending its data. w2.CONFIRM may or may not
|
||||
# have arrived by then
|
||||
yield d1
|
||||
try:
|
||||
yield d1
|
||||
except WrongPasswordError:
|
||||
pass
|
||||
|
||||
# When we ask w1 to get_data(), one of two things might happen:
|
||||
# * if w2.CONFIRM arrived already, it will have recorded the error.
|
||||
|
@ -167,21 +176,6 @@ class Basic(ServerBase, unittest.TestCase):
|
|||
self.assertEqual(dataY, b"data1")
|
||||
yield self.doBoth(w1.close(), w2.close())
|
||||
|
||||
@inlineCallbacks
|
||||
def test_verifier_mismatch(self):
|
||||
w1 = Wormhole(APPID, self.relayurl)
|
||||
w2 = Wormhole(APPID, self.relayurl)
|
||||
# we must disable confirmation messages, else the wormholes will
|
||||
# figure out the mismatch by themselves and throw WrongPasswordError.
|
||||
w1._send_confirm = w2._send_confirm = False
|
||||
code = yield w1.get_code()
|
||||
w2.set_code(code+"not")
|
||||
res = yield self.doBoth(w1.get_verifier(), w2.get_verifier())
|
||||
v1, v2 = res
|
||||
self.failUnlessEqual(type(v1), type(b""))
|
||||
self.failIfEqual(v1, v2)
|
||||
yield self.doBoth(w1.close(), w2.close())
|
||||
|
||||
@inlineCallbacks
|
||||
def test_errors(self):
|
||||
w1 = Wormhole(APPID, self.relayurl)
|
||||
|
|
|
@ -350,6 +350,15 @@ class Wormhole:
|
|||
if self._closed: raise UsageError
|
||||
if self._code is None: raise UsageError
|
||||
yield self._get_master_key()
|
||||
# If the caller cares about the verifier, then they'll probably also
|
||||
# willing to wait a moment to see the _confirm message. Each side
|
||||
# sends this as soon as it sees the other's PAKE message. So the
|
||||
# sender should see this hot on the heels of the inbound PAKE message
|
||||
# (a moment after _get_master_key() returns). The receiver will see
|
||||
# this a round-trip after they send their PAKE (because the sender is
|
||||
# using wait=True inside _get_master_key, below: otherwise the sender
|
||||
# might go do some blocking call).
|
||||
yield self._msg_get(u"_confirm")
|
||||
returnValue(self._verifier)
|
||||
|
||||
@inlineCallbacks
|
||||
|
@ -369,7 +378,7 @@ class Wormhole:
|
|||
confkey = self.derive_key(u"wormhole:confirmation")
|
||||
nonce = os.urandom(CONFMSG_NONCE_LENGTH)
|
||||
confmsg = make_confmsg(confkey, nonce)
|
||||
yield self._msg_send(u"_confirm", confmsg)
|
||||
yield self._msg_send(u"_confirm", confmsg, wait=True)
|
||||
|
||||
@inlineCallbacks
|
||||
def _msg_send(self, phase, body, wait=False):
|
||||
|
@ -396,6 +405,9 @@ class Wormhole:
|
|||
return self._signal_error(err)
|
||||
self._received_messages[phase] = body
|
||||
if phase == u"_confirm":
|
||||
# TODO: we might not have a master key yet, if the caller wasn't
|
||||
# waiting in _get_master_key() when a back-to-back pake+_confirm
|
||||
# message pair arrived.
|
||||
confkey = self.derive_key(u"wormhole:confirmation")
|
||||
nonce = body[:CONFMSG_NONCE_LENGTH]
|
||||
if body != make_confmsg(confkey, nonce):
|
||||
|
|
Loading…
Reference in New Issue
Block a user