implement w.derive_key()
This commit is contained in:
parent
0474c39bab
commit
60a61c995b
|
@ -63,7 +63,7 @@ digraph {
|
||||||
|
|
||||||
{rank=same; Other S_closed}
|
{rank=same; Other S_closed}
|
||||||
Other [shape="box" style="dashed"
|
Other [shape="box" style="dashed"
|
||||||
label="rx_welcome -> process\nsend -> S.send\ngot_verifier -> W.got_verifier\nallocate -> C.allocate\ninput -> C.input\nset_code -> C.set_code"
|
label="rx_welcome -> process\nsend -> S.send\ngot_key -> W.got_key\ngot_verifier -> W.got_verifier\nallocate -> C.allocate\ninput -> C.input\nset_code -> C.set_code"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ digraph {
|
||||||
S1 -> P1_compute [label="got_pake\npake good"]
|
S1 -> P1_compute [label="got_pake\npake good"]
|
||||||
#S1 -> P_mood_lonely [label="close"]
|
#S1 -> P_mood_lonely [label="close"]
|
||||||
|
|
||||||
P1_compute [label="compute_key\nM.add_message(version)\nW.got_verifier\nR.got_key" shape="box"]
|
P1_compute [label="compute_key\nM.add_message(version)\nB.got_key\nB.got_verifier\nR.got_key" shape="box"]
|
||||||
P1_compute -> S2
|
P1_compute -> S2
|
||||||
|
|
||||||
S2 [label="S2: know_key" color="green"]
|
S2 [label="S2: know_key" color="green"]
|
||||||
|
|
|
@ -21,7 +21,7 @@ digraph {
|
||||||
|
|
||||||
Wormhole -> Boss [style="dashed" label="allocate_code\ninput_code\nset_code\nsend\nclose\n(once)"]
|
Wormhole -> Boss [style="dashed" label="allocate_code\ninput_code\nset_code\nsend\nclose\n(once)"]
|
||||||
#Wormhole -> Boss [color="blue"]
|
#Wormhole -> Boss [color="blue"]
|
||||||
Boss -> Wormhole [style="dashed" label="got_code\ngot_verifier\nreceived (seq)\nclosed\n(once)"]
|
Boss -> Wormhole [style="dashed" label="got_code\ngot_key\ngot_verifier\nreceived (seq)\nclosed\n(once)"]
|
||||||
|
|
||||||
#Boss -> Connection [color="blue"]
|
#Boss -> Connection [color="blue"]
|
||||||
Boss -> Connection [style="dashed" label="start"]
|
Boss -> Connection [style="dashed" label="start"]
|
||||||
|
@ -33,7 +33,7 @@ digraph {
|
||||||
#Boss -> Mailbox [color="blue"]
|
#Boss -> Mailbox [color="blue"]
|
||||||
Mailbox -> Order [style="dashed" label="got_message (once)"]
|
Mailbox -> Order [style="dashed" label="got_message (once)"]
|
||||||
Boss -> Key [style="dashed" label="got_code"]
|
Boss -> Key [style="dashed" label="got_code"]
|
||||||
Key -> Boss [style="dashed" label="got_verifier\nscared"]
|
Key -> Boss [style="dashed" label="got_key\ngot_verifier\nscared"]
|
||||||
Order -> Key [style="dashed" label="got_pake"]
|
Order -> Key [style="dashed" label="got_pake"]
|
||||||
Order -> Receive [style="dashed" label="got_message"]
|
Order -> Receive [style="dashed" label="got_message"]
|
||||||
#Boss -> Key [color="blue"]
|
#Boss -> Key [color="blue"]
|
||||||
|
|
|
@ -135,7 +135,7 @@ class Boss(object):
|
||||||
@m.input()
|
@m.input()
|
||||||
def got_code(self, code): pass
|
def got_code(self, code): pass
|
||||||
|
|
||||||
# Key sends (got_verifier, scared)
|
# Key sends (got_key, got_verifier, scared)
|
||||||
# Receive sends (got_message, happy, scared)
|
# Receive sends (got_message, happy, scared)
|
||||||
@m.input()
|
@m.input()
|
||||||
def happy(self): pass
|
def happy(self): pass
|
||||||
|
@ -158,6 +158,8 @@ class Boss(object):
|
||||||
@m.input()
|
@m.input()
|
||||||
def got_phase(self, phase, plaintext): pass
|
def got_phase(self, phase, plaintext): pass
|
||||||
@m.input()
|
@m.input()
|
||||||
|
def got_key(self, key): pass
|
||||||
|
@m.input()
|
||||||
def got_verifier(self, verifier): pass
|
def got_verifier(self, verifier): pass
|
||||||
|
|
||||||
# Terminator sends closed
|
# Terminator sends closed
|
||||||
|
@ -205,6 +207,9 @@ class Boss(object):
|
||||||
self._T.close("happy")
|
self._T.close("happy")
|
||||||
|
|
||||||
@m.output()
|
@m.output()
|
||||||
|
def W_got_key(self, key):
|
||||||
|
self._W.got_key(key)
|
||||||
|
@m.output()
|
||||||
def W_got_verifier(self, verifier):
|
def W_got_verifier(self, verifier):
|
||||||
self._W.got_verifier(verifier)
|
self._W.got_verifier(verifier)
|
||||||
@m.output()
|
@m.output()
|
||||||
|
@ -238,6 +243,7 @@ class Boss(object):
|
||||||
S1_lonely.upon(scared, enter=S3_closing, outputs=[close_scared])
|
S1_lonely.upon(scared, enter=S3_closing, outputs=[close_scared])
|
||||||
S1_lonely.upon(close, enter=S3_closing, outputs=[close_lonely])
|
S1_lonely.upon(close, enter=S3_closing, outputs=[close_lonely])
|
||||||
S1_lonely.upon(send, enter=S1_lonely, outputs=[S_send])
|
S1_lonely.upon(send, enter=S1_lonely, outputs=[S_send])
|
||||||
|
S1_lonely.upon(got_key, enter=S1_lonely, outputs=[W_got_key])
|
||||||
S1_lonely.upon(got_verifier, enter=S1_lonely, outputs=[W_got_verifier])
|
S1_lonely.upon(got_verifier, enter=S1_lonely, outputs=[W_got_verifier])
|
||||||
S1_lonely.upon(rx_error, enter=S3_closing, outputs=[close_error])
|
S1_lonely.upon(rx_error, enter=S3_closing, outputs=[close_error])
|
||||||
S1_lonely.upon(error, enter=S4_closed, outputs=[W_close_with_error])
|
S1_lonely.upon(error, enter=S4_closed, outputs=[W_close_with_error])
|
||||||
|
|
|
@ -110,6 +110,7 @@ class Key(object):
|
||||||
assert isinstance(msg2, type(b""))
|
assert isinstance(msg2, type(b""))
|
||||||
with self._timing.add("pake2", waiting="crypto"):
|
with self._timing.add("pake2", waiting="crypto"):
|
||||||
key = self._sp.finish(msg2)
|
key = self._sp.finish(msg2)
|
||||||
|
self._B.got_key(key)
|
||||||
self._B.got_verifier(derive_key(key, b"wormhole:verifier"))
|
self._B.got_verifier(derive_key(key, b"wormhole:verifier"))
|
||||||
phase = "version"
|
phase = "version"
|
||||||
data_key = derive_phase_key(key, self._side, phase)
|
data_key = derive_phase_key(key, self._side, phase)
|
||||||
|
|
|
@ -50,3 +50,6 @@ class TransferError(WormholeError):
|
||||||
|
|
||||||
class NoTorError(WormholeError):
|
class NoTorError(WormholeError):
|
||||||
"""--tor was requested, but 'txtorcon' is not installed."""
|
"""--tor was requested, but 'txtorcon' is not installed."""
|
||||||
|
|
||||||
|
class NoKeyError(WormholeError):
|
||||||
|
"""w.derive_key() was called before got_verifier() fired"""
|
||||||
|
|
|
@ -147,7 +147,7 @@ class Key(unittest.TestCase):
|
||||||
def build(self):
|
def build(self):
|
||||||
events = []
|
events = []
|
||||||
k = _key.Key(u"appid", u"side", timing.DebugTiming())
|
k = _key.Key(u"appid", u"side", timing.DebugTiming())
|
||||||
b = Dummy("b", events, IBoss, "scared", "got_verifier")
|
b = Dummy("b", events, IBoss, "scared", "got_key", "got_verifier")
|
||||||
m = Dummy("m", events, IMailbox, "add_message")
|
m = Dummy("m", events, IMailbox, "add_message")
|
||||||
r = Dummy("r", events, IReceive, "got_key")
|
r = Dummy("r", events, IReceive, "got_key")
|
||||||
k.wire(b, m, r)
|
k.wire(b, m, r)
|
||||||
|
@ -168,10 +168,11 @@ class Key(unittest.TestCase):
|
||||||
key2 = sp.finish(msg1_bytes)
|
key2 = sp.finish(msg1_bytes)
|
||||||
msg2 = dict_to_bytes({"pake_v1": bytes_to_hexstr(msg2_bytes)})
|
msg2 = dict_to_bytes({"pake_v1": bytes_to_hexstr(msg2_bytes)})
|
||||||
k.got_pake(msg2)
|
k.got_pake(msg2)
|
||||||
self.assertEqual(len(events), 3)
|
self.assertEqual(len(events), 4, events)
|
||||||
self.assertEqual(events[0][0], "b.got_verifier")
|
self.assertEqual(events[0], ("b.got_key", key2))
|
||||||
self.assertEqual(events[1][:2], ("m.add_message", "version"))
|
self.assertEqual(events[1][0], "b.got_verifier")
|
||||||
self.assertEqual(events[2], ("r.got_key", key2))
|
self.assertEqual(events[2][:2], ("m.add_message", "version"))
|
||||||
|
self.assertEqual(events[3], ("r.got_key", key2))
|
||||||
|
|
||||||
|
|
||||||
def test_bad(self):
|
def test_bad(self):
|
||||||
|
|
|
@ -9,6 +9,9 @@ from .util import bytes_to_hexstr
|
||||||
from .timing import DebugTiming
|
from .timing import DebugTiming
|
||||||
from .journal import ImmediateJournal
|
from .journal import ImmediateJournal
|
||||||
from ._boss import Boss
|
from ._boss import Boss
|
||||||
|
from ._key import derive_key
|
||||||
|
from .errors import NoKeyError
|
||||||
|
from .util import to_bytes
|
||||||
|
|
||||||
# We can provide different APIs to different apps:
|
# We can provide different APIs to different apps:
|
||||||
# * Deferreds
|
# * Deferreds
|
||||||
|
@ -39,6 +42,9 @@ def _log(client_name, machine_name, old_state, input, new_state):
|
||||||
class _DelegatedWormhole(object):
|
class _DelegatedWormhole(object):
|
||||||
_delegate = attrib()
|
_delegate = attrib()
|
||||||
|
|
||||||
|
def __attrs_post_init__(self):
|
||||||
|
self._key = None
|
||||||
|
|
||||||
def _set_boss(self, boss):
|
def _set_boss(self, boss):
|
||||||
self._boss = boss
|
self._boss = boss
|
||||||
|
|
||||||
|
@ -59,6 +65,18 @@ class _DelegatedWormhole(object):
|
||||||
|
|
||||||
def send(self, plaintext):
|
def send(self, plaintext):
|
||||||
self._boss.send(plaintext)
|
self._boss.send(plaintext)
|
||||||
|
|
||||||
|
def derive_key(self, purpose, length):
|
||||||
|
"""Derive a new key from the established wormhole channel for some
|
||||||
|
other purpose. This is a deterministic randomized function of the
|
||||||
|
session key and the 'purpose' string (unicode/py3-string). This
|
||||||
|
cannot be called until when_verifier() has fired, nor after close()
|
||||||
|
was called.
|
||||||
|
"""
|
||||||
|
if not isinstance(purpose, type("")): raise TypeError(type(purpose))
|
||||||
|
if not self._key: raise NoKeyError()
|
||||||
|
return derive_key(self._key, to_bytes(purpose), length)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._boss.close()
|
self._boss.close()
|
||||||
|
|
||||||
|
@ -69,6 +87,8 @@ class _DelegatedWormhole(object):
|
||||||
# from below
|
# from below
|
||||||
def got_code(self, code):
|
def got_code(self, code):
|
||||||
self._delegate.wormhole_got_code(code)
|
self._delegate.wormhole_got_code(code)
|
||||||
|
def got_key(self, key):
|
||||||
|
self._key = key # for derive_key()
|
||||||
def got_verifier(self, verifier):
|
def got_verifier(self, verifier):
|
||||||
self._delegate.wormhole_got_verifier(verifier)
|
self._delegate.wormhole_got_verifier(verifier)
|
||||||
def received(self, plaintext):
|
def received(self, plaintext):
|
||||||
|
@ -84,6 +104,7 @@ class _DeferredWormhole(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._code = None
|
self._code = None
|
||||||
self._code_observers = []
|
self._code_observers = []
|
||||||
|
self._key = None
|
||||||
self._verifier = None
|
self._verifier = None
|
||||||
self._verifier_observers = []
|
self._verifier_observers = []
|
||||||
self._received_data = []
|
self._received_data = []
|
||||||
|
@ -125,6 +146,18 @@ class _DeferredWormhole(object):
|
||||||
# no .serialize in Deferred-mode
|
# no .serialize in Deferred-mode
|
||||||
def send(self, plaintext):
|
def send(self, plaintext):
|
||||||
self._boss.send(plaintext)
|
self._boss.send(plaintext)
|
||||||
|
|
||||||
|
def derive_key(self, purpose, length):
|
||||||
|
"""Derive a new key from the established wormhole channel for some
|
||||||
|
other purpose. This is a deterministic randomized function of the
|
||||||
|
session key and the 'purpose' string (unicode/py3-string). This
|
||||||
|
cannot be called until when_verifier() has fired, nor after close()
|
||||||
|
was called.
|
||||||
|
"""
|
||||||
|
if not isinstance(purpose, type("")): raise TypeError(type(purpose))
|
||||||
|
if not self._key: raise NoKeyError()
|
||||||
|
return derive_key(self._key, to_bytes(purpose), length)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
# fails with WormholeError unless we established a connection
|
# fails with WormholeError unless we established a connection
|
||||||
# (state=="happy"). Fails with WrongPasswordError (a subclass of
|
# (state=="happy"). Fails with WrongPasswordError (a subclass of
|
||||||
|
@ -144,6 +177,8 @@ class _DeferredWormhole(object):
|
||||||
for d in self._code_observers:
|
for d in self._code_observers:
|
||||||
d.callback(code)
|
d.callback(code)
|
||||||
self._code_observers[:] = []
|
self._code_observers[:] = []
|
||||||
|
def got_key(self, key):
|
||||||
|
self._key = key # for derive_key()
|
||||||
def got_verifier(self, verifier):
|
def got_verifier(self, verifier):
|
||||||
self._verifier = verifier
|
self._verifier = verifier
|
||||||
for d in self._verifier_observers:
|
for d in self._verifier_observers:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user