diff options
author | joe <joe@jerkface.net> | 2017-09-04 15:36:25 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-09-04 15:36:25 -0400 |
commit | 2e0d1e945c4c0e298176d58cf68df8191b698c1a (patch) | |
tree | ea24bd2dd0a7c924367a0c29ef79bf47eebabdb1 /OnionTransport.hs | |
parent | 8275e9b026b9cce76c326938ed208990cce17587 (diff) |
Fleshed out some Onion Transport stubs.
Diffstat (limited to 'OnionTransport.hs')
-rw-r--r-- | OnionTransport.hs | 133 |
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 | |||
35 | import ToxCrypto hiding (encrypt,decrypt) | 35 | import ToxCrypto hiding (encrypt,decrypt) |
36 | import ToxAddress | 36 | import ToxAddress |
37 | import qualified ToxCrypto | 37 | import qualified ToxCrypto |
38 | import DHTTransport (NodeInfo(..),NodeId(..),SendNodes,nodeInfo) | 38 | import DHTTransport (NodeInfo(..),NodeId(..),SendNodes,nodeInfo,DHTPublicKey) |
39 | 39 | ||
40 | import Control.Arrow | 40 | import Control.Arrow |
41 | import qualified Data.ByteString as B | 41 | import qualified Data.ByteString as B |
42 | ;import Data.ByteString (ByteString) | 42 | ;import Data.ByteString (ByteString) |
43 | import Data.Coerce | ||
44 | import Data.Functor.Contravariant | ||
43 | import Data.Functor.Identity | 45 | import Data.Functor.Identity |
46 | import Data.Monoid | ||
44 | import Data.Serialize as S | 47 | import Data.Serialize as S |
45 | import Data.Typeable | 48 | import Data.Typeable |
46 | import Data.Word | 49 | import 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 | ||
75 | instance 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 | ||
73 | onionToOwner :: Assym a -> ReturnPath 3 -> SockAddr -> Either String OnionToOwner | 86 | onionToOwner :: Assym a -> ReturnPath 3 -> SockAddr -> Either String OnionToOwner |
74 | onionToOwner assym ret3 saddr = do | 87 | onionToOwner 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 | ||
116 | getOnionReply :: Word8 -> Get (OnionMessage Encrypted) | ||
117 | getOnionReply 0x84 = OnionAnnounceResponse <$> get <*> get <*> get | ||
118 | getOnionReply 0x86 = OnionToRouteResponse <$> getOnionAssym | ||
119 | |||
120 | putOnionMsg :: OnionMessage Encrypted -> Put | ||
121 | putOnionMsg (OnionAnnounce a) = putOnionAssym 0x83 (return ()) a | ||
122 | putOnionMsg (OnionToRoute pubkey a) = putOnionAssym 0x85 (putPublicKey pubkey) a | ||
123 | putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x | ||
124 | putOnionMsg (OnionToRouteResponse a) = putOnionAssym 0x86 (return ()) a | ||
125 | |||
103 | encodeOnionAddr :: (OnionMessage Encrypted,OnionToOwner) -> (ByteString, SockAddr) | 126 | encodeOnionAddr :: (OnionMessage Encrypted,OnionToOwner) -> (ByteString, SockAddr) |
104 | encodeOnionAddr (msg,addr) = ( runPut (putmsg >> putpath), saddr ) | 127 | encodeOnionAddr (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 | |||
114 | forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport -- HandleHi a -> IO a -> HandleLo a | 132 | forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport -- HandleHi a -> IO a -> HandleLo a |
115 | forwardOnions crypto udp = udp { awaitMessage = await' } | 133 | forwardOnions 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 | ||
131 | forward :: forall c b b1. | 149 | forward :: 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 |
134 | forward forMe bs f = either (forMe . Just . Left) f $ decode $ B.tail bs | 151 | forward 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 | ||
157 | instance ( KnownNat n, Serialize (ReturnPath n) ) => Serialize (OnionResponse n) where | 174 | instance ( 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 | ||
162 | data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } | 179 | data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } |
163 | 180 | ||
181 | instance 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 | |||
164 | data ReturnPath (n :: Nat) where | 186 | data 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 | ||
168 | instance 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) | 191 | instance KnownNat n => Sized (ReturnPath n) where |
192 | size = ConstSize $ 59 * fromIntegral (natVal (Proxy :: Proxy n)) | ||
193 | |||
194 | instance Serialize (ReturnPath 0) where get = pure NoReturnPath | ||
195 | put NoReturnPath = pure () | ||
196 | |||
197 | instance Serialize (ReturnPath 1) where get = ReturnPath <$> get <*> get | ||
198 | put (ReturnPath n24 p) = put n24 >> put p | ||
170 | 199 | ||
200 | instance Serialize (ReturnPath 2) where get = ReturnPath <$> get <*> get | ||
201 | put (ReturnPath n24 p) = put n24 >> put p | ||
202 | |||
203 | instance 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) | ||
171 | instance (Serialize (Encrypted (Addressed (ReturnPath (n - 1))))) => Serialize (ReturnPath n) where | 208 | instance (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 | ||
175 | instance KnownNat n => Show (ReturnPath n) where | 213 | instance 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 | ||
189 | instance (KnownNat n, Sized msg) => Sized (Addressed (Forwarding n msg)) where size = _todo | 227 | instance Sized msg => Sized (Forwarding 0 msg) |
190 | 228 | where size = case size :: Size msg of | |
191 | instance (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 | ||
231 | instance 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 | ||
235 | instance 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 | ||
239 | instance 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 | |||
245 | instance (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 | ||
208 | instance Sized AnnounceRequest where size = _todo | 262 | instance Sized AnnounceRequest where size = ConstSize (32*3) |
209 | 263 | ||
210 | instance S.Serialize AnnounceRequest where | 264 | instance 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 | ||
214 | getOnionRequest :: Sized msg => Get (Assym (Encrypted msg), ReturnPath 3) | 268 | getOnionRequest :: Sized msg => Get (Assym (Encrypted msg), ReturnPath 3) |
215 | getOnionRequest = (,) <$> getAliasedAssym <*> _todo | 269 | getOnionRequest = 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 | ||
217 | data KeyRecord = NotStored Nonce32 | 278 | data KeyRecord = NotStored Nonce32 |
218 | | SendBackKey PublicKey | 279 | | SendBackKey PublicKey |
219 | | Acknowledged Nonce32 | 280 | | Acknowledged Nonce32 |
220 | 281 | ||
282 | instance Sized KeyRecord where size = ConstSize 33 | ||
283 | |||
221 | instance S.Serialize KeyRecord where | 284 | instance 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 | ||
237 | instance Sized AnnounceResponse where | 300 | instance Sized AnnounceResponse where |
238 | size = VarSize $ \AnnounceResponse {} -> _todo | 301 | size = contramap is_stored size <> contramap announceNodes size |
239 | 302 | ||
240 | instance S.Serialize AnnounceResponse where | 303 | instance 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 | ||
244 | data DataToRoute = DataToRoute | 307 | data 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 | ||
249 | instance Sized DataToRoute where | 312 | instance Sized DataToRoute where |
250 | size = VarSize $ \DataToRoute {} -> _todo | 313 | size = ConstSize 32 <> contramap dataToRoute size |
251 | 314 | ||
252 | instance Serialize DataToRoute where | 315 | instance 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 | |||
319 | data OnionData = OnionDHTPublicKey DHTPublicKey -- 0x9c | ||
320 | |||
321 | instance 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 | ||
256 | encrypt :: TransportCrypto -> OnionMessage Identity -> OnionToOwner -> (OnionMessage Encrypted, OnionToOwner) | 327 | encrypt :: TransportCrypto -> OnionMessage Identity -> OnionToOwner -> (OnionMessage Encrypted, OnionToOwner) |
257 | encrypt crypto msg rpath = (transcode (encryptMessage crypto) msg, rpath) | 328 | encrypt 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 |
265 | encryptMessage crypto n (Left x) = ToxCrypto.encrypt secret plain | 336 | encryptMessage 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 | ||
270 | decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionToOwner -> Either String (OnionMessage Identity, OnionToOwner) | 341 | decrypt :: 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) |
283 | decryptMessage crypto n (Left e) = _todo | 354 | decryptMessage crypto n (Left e) = _todo -- OnionAnnounceResponse has no sender key |
284 | 355 | ||
285 | 356 | ||
286 | sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f) | 357 | sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f) |