tests: exercise Key receiving PAKE before set_code

This commit is contained in:
Brian Warner 2017-04-06 10:44:04 -07:00
parent 0da9cbdeeb
commit df1b2338b1
4 changed files with 61 additions and 2 deletions

View File

@ -69,6 +69,7 @@ class Key(object):
def __attrs_post_init__(self): def __attrs_post_init__(self):
self._SK = _SortedKey(self._appid, self._versions, self._side, self._SK = _SortedKey(self._appid, self._versions, self._side,
self._timing) self._timing)
self._debug_pake_stashed = False # for tests
def wire(self, boss, mailbox, receive): def wire(self, boss, mailbox, receive):
self._SK.wire(boss, mailbox, receive) self._SK.wire(boss, mailbox, receive)
@ -90,6 +91,7 @@ class Key(object):
@m.output() @m.output()
def stash_pake(self, body): def stash_pake(self, body):
self._pake = body self._pake = body
self._debug_pake_stashed = True
@m.output() @m.output()
def deliver_code(self, code): def deliver_code(self, code):
self._SK.got_code(code) self._SK.got_code(code)

View File

@ -1,6 +1,6 @@
# no unicode_literals untill twisted update # no unicode_literals untill twisted update
from twisted.application import service from twisted.application import service
from twisted.internet import defer, task from twisted.internet import defer, task, reactor
from twisted.python import log from twisted.python import log
from click.testing import CliRunner from click.testing import CliRunner
import mock import mock
@ -84,3 +84,10 @@ def config(*argv):
cfg = go.call_args[0][1] cfg = go.call_args[0][1]
return cfg return cfg
@defer.inlineCallbacks
def poll_until(predicate):
# return a Deferred that won't fire until the predicate is True
while not predicate():
d = defer.Deferred()
reactor.callLater(0.001, d.callback, None)
yield d

View File

@ -257,6 +257,34 @@ class Key(unittest.TestCase):
k.got_pake(dict_to_bytes(bad_pake_d)) k.got_pake(dict_to_bytes(bad_pake_d))
self.assertEqual(events, [("b.scared",)]) self.assertEqual(events, [("b.scared",)])
def test_reversed(self):
# A receiver using input_code() will choose the nameplate first, then
# the rest of the code. Once the nameplate is selected, we'll claim
# it and open the mailbox, which will cause the senders PAKE to
# arrive before the code has been set. Key() is supposed to stash the
# PAKE message until the code is set (allowing the PAKE computation
# to finish). This test exercises that PAKE-then-code sequence.
k, b, m, r, events = self.build()
code = u"1-foo"
sp = SPAKE2_Symmetric(to_bytes(code), idSymmetric=to_bytes(u"appid"))
msg2_bytes = sp.start()
msg2 = dict_to_bytes({"pake_v1": bytes_to_hexstr(msg2_bytes)})
k.got_pake(msg2)
self.assertEqual(len(events), 0)
k.got_code(code)
self.assertEqual(len(events), 5)
self.assertEqual(events[0][:2], ("m.add_message", "pake"))
msg1_json = events[0][2].decode("utf-8")
msg1 = json.loads(msg1_json)
msg1_bytes = hexstr_to_bytes(msg1["pake_v1"])
key2 = sp.finish(msg1_bytes)
self.assertEqual(events[1], ("b.got_key", key2))
self.assertEqual(events[2][0], "b.got_verifier")
self.assertEqual(events[3][:2], ("m.add_message", "version"))
self.assertEqual(events[4], ("r.got_key", key2))
class Code(unittest.TestCase): class Code(unittest.TestCase):
def build(self): def build(self):
events = [] events = []

View File

@ -4,7 +4,7 @@ import mock
from twisted.trial import unittest from twisted.trial import unittest
from twisted.internet import reactor from twisted.internet import reactor
from twisted.internet.defer import gatherResults, inlineCallbacks from twisted.internet.defer import gatherResults, inlineCallbacks
from .common import ServerBase from .common import ServerBase, poll_until
from .. import wormhole, _rendezvous from .. import wormhole, _rendezvous
from ..errors import (WrongPasswordError, from ..errors import (WrongPasswordError,
KeyFormatError, WormholeClosed, LonelyError, KeyFormatError, WormholeClosed, LonelyError,
@ -234,6 +234,28 @@ class Wormholes(ServerBase, unittest.TestCase):
yield w1.close() yield w1.close()
yield w2.close() yield w2.close()
@inlineCallbacks
def test_input_code(self):
w1 = wormhole.create(APPID, self.relayurl, reactor)
w2 = wormhole.create(APPID, self.relayurl, reactor)
w1.set_code("123-purple-elephant")
h = w2.input_code()
h.choose_nameplate("123")
# Pause to allow some messages to get delivered. Specifically we want
# to wait until w2 claims the nameplate, opens the mailbox, and
# receives the PAKE message, to exercise the PAKE-before-CODE path in
# Key.
yield poll_until(lambda: w2._boss._K._debug_pake_stashed)
h.choose_words("purple-elephant")
w1.send(b"data1"), w2.send(b"data2")
dl = yield self.doBoth(w1.when_received(), w2.when_received())
(dataX, dataY) = dl
self.assertEqual(dataX, b"data2")
self.assertEqual(dataY, b"data1")
yield w1.close()
yield w2.close()
@inlineCallbacks @inlineCallbacks
def test_multiple_messages(self): def test_multiple_messages(self):