summaryrefslogtreecommitdiff
path: root/OnionTransport.hs
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-09-04 15:36:25 -0400
committerjoe <joe@jerkface.net>2017-09-04 15:36:25 -0400
commit2e0d1e945c4c0e298176d58cf68df8191b698c1a (patch)
treeea24bd2dd0a7c924367a0c29ef79bf47eebabdb1 /OnionTransport.hs
parent8275e9b026b9cce76c326938ed208990cce17587 (diff)
Fleshed out some Onion Transport stubs.
Diffstat (limited to 'OnionTransport.hs')
-rw-r--r--OnionTransport.hs133
1 files changed, 102 insertions, 31 deletions
diff --git a/OnionTransport.hs b/OnionTransport.hs
index d6f6671e..7a837a2b 100644
--- a/OnionTransport.hs
+++ b/OnionTransport.hs
@@ -35,12 +35,15 @@ import Network.QueryResponse
35import ToxCrypto hiding (encrypt,decrypt) 35import ToxCrypto hiding (encrypt,decrypt)
36import ToxAddress 36import ToxAddress
37import qualified ToxCrypto 37import qualified ToxCrypto
38import DHTTransport (NodeInfo(..),NodeId(..),SendNodes,nodeInfo) 38import DHTTransport (NodeInfo(..),NodeId(..),SendNodes,nodeInfo,DHTPublicKey)
39 39
40import Control.Arrow 40import Control.Arrow
41import qualified Data.ByteString as B 41import qualified Data.ByteString as B
42 ;import Data.ByteString (ByteString) 42 ;import Data.ByteString (ByteString)
43import Data.Coerce
44import Data.Functor.Contravariant
43import Data.Functor.Identity 45import Data.Functor.Identity
46import Data.Monoid
44import Data.Serialize as S 47import Data.Serialize as S
45import Data.Typeable 48import Data.Typeable
46import Data.Word 49import Data.Word
@@ -69,6 +72,16 @@ data OnionToOwner = OnionToOwner NodeInfo (ReturnPath 3)
69 | OnionToMe SockAddr -- SockAddr is immediate peer in route 72 | OnionToMe SockAddr -- SockAddr is immediate peer in route
70 deriving Show 73 deriving Show
71 74
75instance Sized (OnionMessage Encrypted) where
76 size = VarSize $ \case
77 OnionAnnounce a -> case size of ConstSize n -> n + 1
78 VarSize f -> f a + 1
79 OnionAnnounceResponse n8 n24 x -> case size of ConstSize n -> n + 33
80 VarSize f -> f x + 33
81 OnionToRoute pubkey a -> case size of ConstSize n -> n + 33
82 VarSize f -> f a + 33
83 OnionToRouteResponse a -> case size of ConstSize n -> n + 1
84 VarSize f -> f a + 1
72 85
73onionToOwner :: Assym a -> ReturnPath 3 -> SockAddr -> Either String OnionToOwner 86onionToOwner :: Assym a -> ReturnPath 3 -> SockAddr -> Either String OnionToOwner
74onionToOwner assym ret3 saddr = do 87onionToOwner assym ret3 saddr = do
@@ -94,23 +107,28 @@ parseOnionAddr (msg,saddr)
94 query = either (const right) Left 107 query = either (const right) Left
95 response = either (const right) (Left . (, OnionToMe saddr)) 108 response = either (const right) (Left . (, OnionToMe saddr))
96 = case typ of 109 = case typ of
97 0x83 -> query $ onion bs saddr (pure OnionAnnounce) -- Announce Request 110 0x83 -> query $ onion bs saddr (pure OnionAnnounce) -- Announce Request
98 0x85 -> query $ onion bs saddr (OnionToRoute <$> getPublicKey) -- Onion Data Request 111 0x85 -> query $ onion bs saddr (OnionToRoute <$> getPublicKey) -- Onion Data Request
99 0x84 -> response $ runGet (OnionAnnounceResponse <$> get <*> get <*> get) bs -- Announce Response 112 0x84 -> response $ runGet (getOnionReply 0x84) bs -- Announce Response
100 0x86 -> response $ runGet (OnionToRouteResponse <$> getOnionAssym) bs -- Onion Data Response 113 0x86 -> response $ runGet (getOnionReply 0x86) bs -- Onion Data Response
101 _ -> right 114 _ -> right
102 115
116getOnionReply :: Word8 -> Get (OnionMessage Encrypted)
117getOnionReply 0x84 = OnionAnnounceResponse <$> get <*> get <*> get
118getOnionReply 0x86 = OnionToRouteResponse <$> getOnionAssym
119
120putOnionMsg :: OnionMessage Encrypted -> Put
121putOnionMsg (OnionAnnounce a) = putOnionAssym 0x83 (return ()) a
122putOnionMsg (OnionToRoute pubkey a) = putOnionAssym 0x85 (putPublicKey pubkey) a
123putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x
124putOnionMsg (OnionToRouteResponse a) = putOnionAssym 0x86 (return ()) a
125
103encodeOnionAddr :: (OnionMessage Encrypted,OnionToOwner) -> (ByteString, SockAddr) 126encodeOnionAddr :: (OnionMessage Encrypted,OnionToOwner) -> (ByteString, SockAddr)
104encodeOnionAddr (msg,addr) = ( runPut (putmsg >> putpath), saddr ) 127encodeOnionAddr (msg,addr) = ( runPut (putOnionMsg msg >> putpath), saddr )
105 where 128 where
106 (saddr,putpath) | OnionToOwner ni p <- addr = (nodeAddr ni, put p) 129 (saddr,putpath) | OnionToOwner ni p <- addr = (nodeAddr ni, put p)
107 | OnionToMe a <- addr = (a, return ()) 130 | OnionToMe a <- addr = (a, return ())
108 131
109 putmsg | OnionAnnounce a <- msg = putOnionAssym 0x83 (return ()) a
110 | OnionToRoute pubkey a <- msg = putOnionAssym 0x85 (putPublicKey pubkey) a
111 | OnionToRouteResponse a <- msg = putOnionAssym 0x86 (return ()) a
112 | OnionAnnounceResponse n8 n24 x <- msg = put (0x84 :: Word8) >> put n8 >> put n24 >> put x
113
114forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport -- HandleHi a -> IO a -> HandleLo a 132forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport -- HandleHi a -> IO a -> HandleLo a
115forwardOnions crypto udp = udp { awaitMessage = await' } 133forwardOnions crypto udp = udp { awaitMessage = await' }
116 where 134 where
@@ -128,8 +146,7 @@ forwardOnions crypto udp = udp { awaitMessage = await' }
128 _ -> forThem m 146 _ -> forThem m
129 m -> forThem m 147 m -> forThem m
130 148
131forward :: forall c b b1. 149forward :: forall c b b1. Serialize b =>
132 Serialize b =>
133 (Maybe (Either String b1) -> c) -> ByteString -> (b -> c) -> c 150 (Maybe (Either String b1) -> c) -> ByteString -> (b -> c) -> c
134forward forMe bs f = either (forMe . Just . Left) f $ decode $ B.tail bs 151forward forMe bs f = either (forMe . Just . Left) f $ decode $ B.tail bs
135 152
@@ -154,23 +171,44 @@ data OnionResponse (n :: Nat) = OnionResponse
154 , msgToOwner :: OnionMessage Encrypted 171 , msgToOwner :: OnionMessage Encrypted
155 } 172 }
156 173
157instance ( KnownNat n, Serialize (ReturnPath n) ) => Serialize (OnionResponse n) where 174instance ( Serialize (ReturnPath n) ) => Serialize (OnionResponse n) where
158 get = OnionResponse <$> get <*> get 175 get = OnionResponse <$> get <*> (get >>= getOnionReply)
159 put (OnionResponse p m) = put p >> put m 176 put (OnionResponse p m) = put p >> putOnionMsg m
160 177
161 178
162data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } 179data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a }
163 180
181instance Sized a => Sized (Addressed a) where
182 size = case size of
183 ConstSize n -> ConstSize $ 1{-family-} + 16{-ip-} + 2{-port-} + n
184 VarSize f -> VarSize $ \x -> 1{-family-} + 16{-ip-} + 2{-port-} + f x
185
164data ReturnPath (n :: Nat) where 186data ReturnPath (n :: Nat) where
165 NoReturnPath :: ReturnPath 0 187 NoReturnPath :: ReturnPath 0
166 ReturnPath :: Nonce24 -> Encrypted (Addressed (ReturnPath (n - 1))) -> ReturnPath n 188 ReturnPath :: Nonce24 -> Encrypted (Addressed (ReturnPath (n - 1))) -> ReturnPath n
167 189
168instance KnownNat n => Sized (Addressed (ReturnPath n)) where size = _todo 190-- Size: 59 = 1(family) + 16(ip) + 2(port) +16(mac) + 24(nonce)
169-- -- Size: 59 = 1(family) + 16(ip) + 2(port) +16(mac) + 24(nonce) 191instance KnownNat n => Sized (ReturnPath n) where
192 size = ConstSize $ 59 * fromIntegral (natVal (Proxy :: Proxy n))
193
194instance Serialize (ReturnPath 0) where get = pure NoReturnPath
195 put NoReturnPath = pure ()
196
197instance Serialize (ReturnPath 1) where get = ReturnPath <$> get <*> get
198 put (ReturnPath n24 p) = put n24 >> put p
170 199
200instance Serialize (ReturnPath 2) where get = ReturnPath <$> get <*> get
201 put (ReturnPath n24 p) = put n24 >> put p
202
203instance Serialize (ReturnPath 3) where get = ReturnPath <$> get <*> get
204 put (ReturnPath n24 p) = put n24 >> put p
205
206{-
207-- This doesn't work because it tried to infer it for (0 - 1)
171instance (Serialize (Encrypted (Addressed (ReturnPath (n - 1))))) => Serialize (ReturnPath n) where 208instance (Serialize (Encrypted (Addressed (ReturnPath (n - 1))))) => Serialize (ReturnPath n) where
172 get = ReturnPath <$> get <*> get 209 get = ReturnPath <$> get <*> get
173 put (ReturnPath n24 p) = put n24 >> put p 210 put (ReturnPath n24 p) = put n24 >> put p
211-}
174 212
175instance KnownNat n => Show (ReturnPath n) where 213instance KnownNat n => Show (ReturnPath n) where
176 show rpath = "ReturnPath" ++ show (natVal rpath) 214 show rpath = "ReturnPath" ++ show (natVal rpath)
@@ -186,9 +224,25 @@ data Forwarding (n :: Nat) msg where
186 NotForwarded :: msg -> Forwarding 0 msg 224 NotForwarded :: msg -> Forwarding 0 msg
187 Forwarding :: Assym (Encrypted (Addressed (Forwarding (n - 1) msg))) -> Forwarding n msg 225 Forwarding :: Assym (Encrypted (Addressed (Forwarding (n - 1) msg))) -> Forwarding n msg
188 226
189instance (KnownNat n, Sized msg) => Sized (Addressed (Forwarding n msg)) where size = _todo 227instance Sized msg => Sized (Forwarding 0 msg)
190 228 where size = case size :: Size msg of
191instance (Serialize msg, Serialize (Encrypted (Addressed (Forwarding (n - 1) msg)))) => Serialize (Forwarding n msg) where 229 ConstSize n -> ConstSize n
230 VarSize f -> VarSize $ \(NotForwarded x) -> f x
231instance Sized msg => Sized (Forwarding 1 msg)
232 where size = case size :: Size (Assym (Encrypted (Addressed (Forwarding 0 msg)))) of
233 ConstSize n -> ConstSize n
234 VarSize f -> VarSize $ \(Forwarding a) -> f a
235instance Sized msg => Sized (Forwarding 2 msg)
236 where size = case size :: Size (Assym (Encrypted (Addressed (Forwarding 1 msg)))) of
237 ConstSize n -> ConstSize n
238 VarSize f -> VarSize $ \(Forwarding a) -> f a
239instance Sized msg => Sized (Forwarding 3 msg)
240 where size = case size :: Size (Assym (Encrypted (Addressed (Forwarding 2 msg)))) of
241 ConstSize n -> ConstSize n
242 VarSize f -> VarSize $ \(Forwarding a) -> f a
243
244
245instance (Serialize (Encrypted (Addressed (Forwarding (n - 1) msg)))) => Serialize (Forwarding n msg) where
192 get = Forwarding <$> getAliasedAssym 246 get = Forwarding <$> getAliasedAssym
193 put (Forwarding x) = putAliasedAssym x 247 put (Forwarding x) = putAliasedAssym x
194 248
@@ -205,19 +259,28 @@ data AnnounceRequest = AnnounceRequest
205 , announceKey :: NodeId -- Public key that we want those sending back data packets to use 259 , announceKey :: NodeId -- Public key that we want those sending back data packets to use
206 } 260 }
207 261
208instance Sized AnnounceRequest where size = _todo 262instance Sized AnnounceRequest where size = ConstSize (32*3)
209 263
210instance S.Serialize AnnounceRequest where 264instance S.Serialize AnnounceRequest where
211 get = AnnounceRequest <$> S.get <*> S.get <*> S.get 265 get = AnnounceRequest <$> S.get <*> S.get <*> S.get
212 put (AnnounceRequest p s k) = S.put (p,s,k) 266 put (AnnounceRequest p s k) = S.put (p,s,k)
213 267
214getOnionRequest :: Sized msg => Get (Assym (Encrypted msg), ReturnPath 3) 268getOnionRequest :: Sized msg => Get (Assym (Encrypted msg), ReturnPath 3)
215getOnionRequest = (,) <$> getAliasedAssym <*> _todo 269getOnionRequest = do
270 -- Assumes return path is constant size so that we can isolate
271 -- the variable-sized prefix.
272 cnt <- remaining
273 a <- isolate (case size :: Size (ReturnPath 3) of ConstSize n -> cnt - n)
274 getAliasedAssym
275 path <- get
276 return (a,path)
216 277
217data KeyRecord = NotStored Nonce32 278data KeyRecord = NotStored Nonce32
218 | SendBackKey PublicKey 279 | SendBackKey PublicKey
219 | Acknowledged Nonce32 280 | Acknowledged Nonce32
220 281
282instance Sized KeyRecord where size = ConstSize 33
283
221instance S.Serialize KeyRecord where 284instance S.Serialize KeyRecord where
222 get = do 285 get = do
223 is_stored <- S.get :: S.Get Word8 286 is_stored <- S.get :: S.Get Word8
@@ -235,23 +298,31 @@ data AnnounceResponse = AnnounceResponse
235 } 298 }
236 299
237instance Sized AnnounceResponse where 300instance Sized AnnounceResponse where
238 size = VarSize $ \AnnounceResponse {} -> _todo 301 size = contramap is_stored size <> contramap announceNodes size
239 302
240instance S.Serialize AnnounceResponse where 303instance S.Serialize AnnounceResponse where
241 get = AnnounceResponse <$> S.get <*> S.get 304 get = AnnounceResponse <$> S.get <*> S.get
242 put (AnnounceResponse st ns) = S.put st >> S.put ns 305 put (AnnounceResponse st ns) = S.put st >> S.put ns
243 306
244data DataToRoute = DataToRoute 307data DataToRoute = DataToRoute
245 { dataFromKey :: PublicKey 308 { dataFromKey :: PublicKey -- Real public key of sender
246 , dataToRoute :: Encrypted (Word8,ByteString) 309 , dataToRoute :: Encrypted OnionData -- (Word8,ByteString) -- DHTPK 0x9c
247 } 310 }
248 311
249instance Sized DataToRoute where 312instance Sized DataToRoute where
250 size = VarSize $ \DataToRoute {} -> _todo 313 size = ConstSize 32 <> contramap dataToRoute size
251 314
252instance Serialize DataToRoute where 315instance Serialize DataToRoute where
253 get = return $ DataToRoute _todo _todo 316 get = DataToRoute <$> getPublicKey <*> get
254 put _ = return () -- todo 317 put (DataToRoute k dta) = putPublicKey k >> put dta
318
319data OnionData = OnionDHTPublicKey DHTPublicKey -- 0x9c
320
321instance Sized OnionData where
322 size = VarSize $ \(OnionDHTPublicKey dhtpk) -> case size of
323 ConstSize n -> n -- Override because OnionData probably
324 -- should be treated as variable sized.
325 VarSize f -> f dhtpk
255 326
256encrypt :: TransportCrypto -> OnionMessage Identity -> OnionToOwner -> (OnionMessage Encrypted, OnionToOwner) 327encrypt :: TransportCrypto -> OnionMessage Identity -> OnionToOwner -> (OnionMessage Encrypted, OnionToOwner)
257encrypt crypto msg rpath = (transcode (encryptMessage crypto) msg, rpath) 328encrypt crypto msg rpath = (transcode (encryptMessage crypto) msg, rpath)
@@ -264,7 +335,7 @@ encryptMessage crypto n (Right a) = ToxCrypto.encrypt secret plain
264 plain = encodePlain $ runIdentity $ assymData a 335 plain = encodePlain $ runIdentity $ assymData a
265encryptMessage crypto n (Left x) = ToxCrypto.encrypt secret plain 336encryptMessage crypto n (Left x) = ToxCrypto.encrypt secret plain
266 where 337 where
267 secret = computeSharedSecret (transportSecret crypto) _todo n 338 secret = computeSharedSecret (transportSecret crypto) _todo n -- OnionAnnounceResponse has no sender key
268 plain = encodePlain $ runIdentity $ x 339 plain = encodePlain $ runIdentity $ x
269 340
270decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionToOwner -> Either String (OnionMessage Identity, OnionToOwner) 341decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionToOwner -> Either String (OnionMessage Identity, OnionToOwner)
@@ -280,7 +351,7 @@ decryptMessage crypto n (Right assymE) = plain $ ToxCrypto.decrypt secret e
280 secret = computeSharedSecret (transportSecret crypto) (senderKey assymE) n 351 secret = computeSharedSecret (transportSecret crypto) (senderKey assymE) n
281 e = assymData assymE 352 e = assymData assymE
282 plain = Composed . fmap Identity . (>>= decodePlain) 353 plain = Composed . fmap Identity . (>>= decodePlain)
283decryptMessage crypto n (Left e) = _todo 354decryptMessage crypto n (Left e) = _todo -- OnionAnnounceResponse has no sender key
284 355
285 356
286sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f) 357sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f)