WiP Noise tunnel
This commit is contained in:
parent
2e027afc42
commit
760ce84a8c
|
@ -1,3 +1,3 @@
|
|||
include depends.tup
|
||||
NIM = $(DIRENV) nim
|
||||
NIM = $(DIRENV) $(NIM)
|
||||
NIM_GROUPS += $(TUP_CWD)/<lock>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
include ../preserves-nim/depends.tup
|
||||
NIM_FLAGS += --path:$(TUP_CWD)/../preserves-nim/src
|
||||
NIM_FLAGS += --path:$(TUP_CWD)/../noiseprotocol/src
|
||||
NIM_GROUPS += $(TUP_CWD)/<protocol>
|
||||
|
|
|
@ -298,7 +298,156 @@ proc accepted(cap: Cap): Resolved =
|
|||
result = Resolved(orKind: ResolvedKind.accepted)
|
||||
result.accepted.responderSession = cap
|
||||
|
||||
import syndicate/protocols/noise
|
||||
import noiseprotocol
|
||||
|
||||
type
|
||||
NoiseTunnelEntity = ref object of Entity
|
||||
handshake: HandshakeState
|
||||
sendCipher, recvCipher: CipherState
|
||||
peer: Cap
|
||||
relay: Relay
|
||||
action: ACTION
|
||||
|
||||
method message(tunnel: NoiseTunnelEntity; turn: var Turn; v: AssertionRef) =
|
||||
doAssert(v.value.isByteString, $v.value)
|
||||
stderr.writeLine "NoiseTunnelEntity: received message of ", v.value.bytes.len, " bytes"
|
||||
|
||||
proc protocolName(spec: NoiseSpec): string =
|
||||
if spec.protocol.isNone: "Noise_NK_25519_ChaChaPoly_BLAKE2s"
|
||||
else: spec.protocol.get.string
|
||||
|
||||
proc handshake(turn: var Turn; tunnel: NoiseTunnelEntity; spec: NoiseSpec; cont: TurnAction) =
|
||||
stderr.writeLine "handshaking"
|
||||
let handshake = spec.protocolName.newByName(INITIATOR)
|
||||
stderr.writeLine "got handshake"
|
||||
handshake.set_prologue(spec.service.encode)
|
||||
stderr.writeLine "prologue set"
|
||||
if spec.preSharedKeys.isSome:
|
||||
stderr.writeLine "spec.preSharedKeys.isSome:"
|
||||
var keys: seq[seq[byte]]
|
||||
stderr.writeLine("get preSharedKeys")
|
||||
if not keys.fromPreserves(get spec.preSharedKeys):
|
||||
raise newException(ValueError, "invalid preSharedKeys in NoiseSpec")
|
||||
for key in keys:
|
||||
handshake.setPreSharedKey(key)
|
||||
stderr.writeLine("get_local_keypair_dh")
|
||||
let dh = handshake.get_remote_public_key_dh
|
||||
if not dh.isNil:
|
||||
dh.set_public_key(spec.key)
|
||||
stderr.writeLine "start handshake"
|
||||
start(handshake)
|
||||
while true:
|
||||
tunnel.action = get_action(handshake)
|
||||
stderr.writeLine("tunnel.action is ", $tunnel.action)
|
||||
case tunnel.action
|
||||
of SPLIT:
|
||||
(tunnel.sendCipher, tunnel.recvCipher) = split(handshake)
|
||||
destroy(handshake)
|
||||
cont(turn)
|
||||
of WRITE_MESSAGE:
|
||||
var buf = newSeqOfCap[byte](256)
|
||||
write_message(handshake, buf, @[])
|
||||
tunnel.peer.target.message(turn, AssertionRef(value: buf.toPreserves))
|
||||
of READ_MESSAGE:
|
||||
break
|
||||
else:
|
||||
raiseAssert("action is " & $tunnel.action)
|
||||
|
||||
#[
|
||||
type
|
||||
NoiseTunnel = ref object
|
||||
buffer: seq[byte]
|
||||
handshake: HandshakeState
|
||||
sendCipher, recvCipher: CipherState
|
||||
|
||||
proc noiseSend(state: NoiseTunnel; buf: seq[byte]) =
|
||||
stderr.writeLine("noise send ", buf.len, " bytes")
|
||||
var state = NoiseTunnel(tun)
|
||||
if not state.handshake.isNil:
|
||||
let action = get_action(state.handshake)
|
||||
case action
|
||||
of SPLIT:
|
||||
(state.sendCipher, state.recvCipher) = split(state.handshake)
|
||||
destroy(state.handshake)
|
||||
send(state, buf)
|
||||
of WRITE_MESSAGE:
|
||||
doAssert(buf.len < MAX_PAYLOAD_LEN)
|
||||
state.buffer.setLen(buf.len)
|
||||
write_message(state.handshake, state.buffer, buf)
|
||||
send(state.inner, state.buffer)
|
||||
else:
|
||||
raiseAssert("bad noise handshake state " & $action)
|
||||
else:
|
||||
doAssert(buf.len < MAX_PAYLOAD_LEN)
|
||||
state.buffer.setLen(buf.len)
|
||||
copyMem(state.buffer[0].addr, buf[0].addr, state.buffer.len)
|
||||
encrypt(state.sendCipher, state.buffer)
|
||||
send(state.inner, state.buffer)
|
||||
|
||||
proc noiseRecv(tun: Tunnel; buf: seq[byte]) =
|
||||
stderr.writeLine("noise recv ", buf.len, " bytes")
|
||||
var state = NoiseTunnel(tun)
|
||||
if not state.handshake.isNil:
|
||||
let action = get_action(state.handshake)
|
||||
case action
|
||||
of SPLIT:
|
||||
(state.sendCipher, state.recvCipher) = split(state.handshake)
|
||||
destroy(state.handshake)
|
||||
send(state, buf)
|
||||
of READ_MESSAGE:
|
||||
doAssert(buf.len < MAX_PAYLOAD_LEN)
|
||||
state.buffer.setLen(buf.len)
|
||||
copyMem(state.buffer[0].addr, buf[0].addr, state.buffer.len)
|
||||
read_message(state.handshake, buf, state.buffer)
|
||||
recv(state.outer, state.buffer)
|
||||
else:
|
||||
raiseAssert("bad noise handshake state " & $action)
|
||||
else:
|
||||
doAssert(buf.len < MAX_PAYLOAD_LEN)
|
||||
state.buffer.setLen(buf.len)
|
||||
copyMem(state.buffer[0].addr, buf[0].addr, state.buffer.len)
|
||||
decrypt(state.sendCipher, state.buffer)
|
||||
recv(state.outer, state.buffer)
|
||||
|
||||
proc newNoiseTunnel(facet: Facet; spec: NoiseSpec): NoiseTunnel =
|
||||
noiseprotocol.init()
|
||||
let state = NoiseTunnel(
|
||||
send: noiseSend,
|
||||
recv: noiseRecv,
|
||||
handshake: spec.protocolName.newByName(INITIATOR)
|
||||
)
|
||||
state.handshake.set_prologue(spec.service.encode)
|
||||
if spec.preSharedKeys.isSome:
|
||||
var keys: seq[seq[byte]]
|
||||
if not keys.fromPreserves(get spec.preSharedKeys):
|
||||
raise newException(ValueError, "invalid preSharedKeys in NoiseSpec")
|
||||
for key in keys:
|
||||
state.handshake.setPreSharedKey(key)
|
||||
if spec.key.len > 0: # responder public key
|
||||
state.handshake.get_local_keypair_dh.set_public_key(spec.key)
|
||||
start(state.handshake)
|
||||
]#
|
||||
|
||||
proc spawnNoiseRelay(turn: var Turn; ds, origin: Cap; spec: NoiseSpec) =
|
||||
let tunnel = NoiseTunnelEntity(peer: origin)
|
||||
proc noiseWriter(turn: var Turn; buf: seq[byte]) =
|
||||
stderr.writeLine "NoiseTunnelEntity: need to send ", buf.len, " bytes"
|
||||
var opts = RelayActorOptions(
|
||||
packetWriter: noiseWriter,
|
||||
initialCap: ds,
|
||||
initialOid: 0.Oid.some,
|
||||
)
|
||||
spawnRelay("noise-relay", turn, opts) do (turn: var Turn; relay: Relay):
|
||||
tunnel.relay = relay
|
||||
#[
|
||||
handshake(turn, tunnel, spec) do (turn: var Turn):
|
||||
publish(turn, ds, ResolvedPathStep(
|
||||
origin: origin,
|
||||
pathStep: toRecord(toSymbol"noise", spec),
|
||||
resolved: tunnel.relay.peer.accepted,
|
||||
))
|
||||
]#
|
||||
|
||||
when defined(posix):
|
||||
|
||||
|
@ -510,6 +659,27 @@ proc spawnRelays*(turn: var Turn; ds: Cap) =
|
|||
observer: newCap(turn, during(duringCallback)),
|
||||
))
|
||||
|
||||
spawn("noise-step", turn) do (turn: var Turn):
|
||||
let
|
||||
stepPat = grabRecord(toSymbol"noise", grab())
|
||||
pat = ?Observe(pattern: ResolvedPathStep?:{1: stepPat}) ?? {0: grab(), 1: grab()}
|
||||
during(turn, ds, pat) do (origin: Literal[Cap]; detail: Literal[NoiseSpec]):
|
||||
let step = toRecord(Symbol"noise", detail.value)
|
||||
proc duringCallback(turn: var Turn; ass: Assertion; h: Handle): TurnAction =
|
||||
# TODO: better during thing
|
||||
let facet = inFacet(turn) do (turn: var Turn):
|
||||
var res = ass.preservesTo Resolved
|
||||
if res.isSome and res.get.orKind == ResolvedKind.accepted:
|
||||
if res.get.accepted.responderSession of Cap:
|
||||
spawnNoiseRelay(turn, ds, res.get.accepted.responderSession.Cap, detail.value)
|
||||
proc action(turn: var Turn) =
|
||||
stop(turn, facet)
|
||||
result = action
|
||||
publish(turn, origin.value, Resolve(
|
||||
step: step,
|
||||
observer: newCap(turn, during(duringCallback)),
|
||||
))
|
||||
|
||||
type BootProc* = proc (turn: var Turn; ds: Cap) {.gcsafe.}
|
||||
|
||||
proc envRoute*: Route =
|
||||
|
|
Loading…
Reference in New Issue