summaryrefslogtreecommitdiff
path: root/src/Network/Tox/Onion/Transport.hs
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-10-01 05:26:36 -0400
committerjoe <joe@jerkface.net>2017-10-01 05:26:36 -0400
commitd408e6c3148106c6dbc8afe24a1488619adf34e1 (patch)
treeca2d7a66b07dba82b6bf236fb234cac75bf87da6 /src/Network/Tox/Onion/Transport.hs
parentf6f70dcfa25ddf10e3cf16745bdd082cc26b2fd6 (diff)
Ability to send onion messages when given a path.
Diffstat (limited to 'src/Network/Tox/Onion/Transport.hs')
-rw-r--r--src/Network/Tox/Onion/Transport.hs151
1 files changed, 105 insertions, 46 deletions
diff --git a/src/Network/Tox/Onion/Transport.hs b/src/Network/Tox/Onion/Transport.hs
index 0e6e4954..a3c1950f 100644
--- a/src/Network/Tox/Onion/Transport.hs
+++ b/src/Network/Tox/Onion/Transport.hs
@@ -33,6 +33,8 @@ module Network.Tox.Onion.Transport
33 , encrypt 33 , encrypt
34 , decrypt 34 , decrypt
35 , peelSymmetric 35 , peelSymmetric
36 , OnionRoute(..)
37 , N3
36 ) where 38 ) where
37 39
38import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) 40import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort)
@@ -86,13 +88,14 @@ deriving instance ( Show (f (AnnounceRequest, Nonce8))
86 , Show (f DataToRoute) 88 , Show (f DataToRoute)
87 ) => Show (OnionMessage f) 89 ) => Show (OnionMessage f)
88 90
89data OnionDestination = OnionToOwner NodeInfo (ReturnPath N3) -- ^ Somebody else's path to us. 91data OnionDestination r
90 | OnionDestination NodeInfo -- ^ Our own onion-path. 92 = OnionToOwner NodeInfo (ReturnPath N3) -- ^ Somebody else's path to us.
93 | OnionDestination NodeInfo (Maybe r) -- ^ Our own onion-path.
91 deriving Show 94 deriving Show
92 95
93onionKey :: OnionDestination -> Maybe PublicKey 96onionKey :: OnionDestination r -> Maybe PublicKey
94onionKey (OnionToOwner ni _) = Just $ id2key (nodeId ni) 97onionKey (OnionToOwner ni _) = Just $ id2key (nodeId ni)
95onionKey _ = Nothing 98onionKey (OnionDestination ni _) = Just $ id2key (nodeId ni)
96 99
97instance Sized (OnionMessage Encrypted) where 100instance Sized (OnionMessage Encrypted) where
98 size = VarSize $ \case 101 size = VarSize $ \case
@@ -111,15 +114,14 @@ instance Serialize (OnionMessage Encrypted) where
111 case typ :: Word8 of 114 case typ :: Word8 of
112 0x83 -> OnionAnnounce <$> getAliasedAssym 115 0x83 -> OnionAnnounce <$> getAliasedAssym
113 0x85 -> OnionToRoute <$> getPublicKey <*> getAliasedAssym 116 0x85 -> OnionToRoute <$> getPublicKey <*> getAliasedAssym
114 0x84 -> getOnionReply typ 117 t -> fail ("Unknown onion payload: " ++ show t)
115 0x86 -> getOnionReply typ 118 `fromMaybe` getOnionReply t
116 t -> fail $ "Unknown onion payload: " ++ show t
117 put (OnionAnnounce a) = putWord8 0x83 >> putAliasedAssym a 119 put (OnionAnnounce a) = putWord8 0x83 >> putAliasedAssym a
118 put (OnionToRoute k a) = putWord8 0x85 >> putPublicKey k >> putAliasedAssym a 120 put (OnionToRoute k a) = putWord8 0x85 >> putPublicKey k >> putAliasedAssym a
119 put (OnionAnnounceResponse n8 n24 x) = putWord8 0x84 >> put n8 >> put n24 >> put x 121 put (OnionAnnounceResponse n8 n24 x) = putWord8 0x84 >> put n8 >> put n24 >> put x
120 put (OnionToRouteResponse a) = putWord8 0x86 >> putAliasedAssym a 122 put (OnionToRouteResponse a) = putWord8 0x86 >> putAliasedAssym a
121 123
122onionToOwner :: Assym a -> ReturnPath N3 -> SockAddr -> Either String OnionDestination 124onionToOwner :: Assym a -> ReturnPath N3 -> SockAddr -> Either String (OnionDestination r)
123onionToOwner assym ret3 saddr = do 125onionToOwner assym ret3 saddr = do
124 ni <- nodeInfo (key2id $ senderKey assym) saddr 126 ni <- nodeInfo (key2id $ senderKey assym) saddr
125 return $ OnionToOwner ni ret3 127 return $ OnionToOwner ni ret3
@@ -130,36 +132,37 @@ onion :: Sized msg =>
130 ByteString 132 ByteString
131 -> SockAddr 133 -> SockAddr
132 -> Get (Assym (Encrypted msg) -> t) 134 -> Get (Assym (Encrypted msg) -> t)
133 -> Either String (t, OnionDestination) 135 -> Either String (t, OnionDestination r)
134onion bs saddr getf = do (f,(assym,ret3)) <- runGet ((,) <$> getf <*> getOnionRequest) bs 136onion bs saddr getf = do (f,(assym,ret3)) <- runGet ((,) <$> getf <*> getOnionRequest) bs
135 oaddr <- onionToOwner assym ret3 saddr 137 oaddr <- onionToOwner assym ret3 saddr
136 return (f assym, oaddr) 138 return (f assym, oaddr)
137 139
138 140parseOnionAddr :: (SockAddr -> Nonce8 -> IO (Maybe (NodeInfo,r)))
139parseOnionAddr :: (ByteString, SockAddr) -> Either (OnionMessage Encrypted,OnionDestination) (ByteString,SockAddr) 141 -> (ByteString, SockAddr)
140parseOnionAddr (msg,saddr) 142 -> IO (Either (OnionMessage Encrypted,OnionDestination r)
143 (ByteString,SockAddr))
144parseOnionAddr lookupSender (msg,saddr)
141 | Just (typ,bs) <- B.uncons msg 145 | Just (typ,bs) <- B.uncons msg
142 , let right = Right (msg,saddr) 146 , let right = Right (msg,saddr)
143 query = either (const right) Left 147 query = return . either (const right) Left
144 response = either (const right) (Left . \msg -> ( msg , replyAlias saddr msg ))
145 = case typ of 148 = case typ of
146 0x83 -> query $ onion bs saddr (pure OnionAnnounce) -- Announce Request 149 0x83 -> query $ onion bs saddr (pure OnionAnnounce) -- Announce Request
147 0x85 -> query $ onion bs saddr (OnionToRoute <$> getPublicKey) -- Onion Data Request 150 0x85 -> query $ onion bs saddr (OnionToRoute <$> getPublicKey) -- Onion Data Request
148 0x84 -> response $ runGet (getOnionReply 0x84) bs -- Announce Response 151 _ -> case flip runGet bs <$> getOnionReply typ of
149 0x86 -> response $ runGet (getOnionReply 0x86) bs -- Onion Data Response 152 Just (Right msg@(OnionAnnounceResponse n8 _ _)) -> do
150 _ -> right 153 maddr <- lookupSender saddr n8
151 154 maybe (return right) -- Response unsolicited or too late.
152getOnionReply :: Word8 -> Get (OnionMessage Encrypted) 155 (return . Left . \(ni,r) -> (msg,OnionDestination ni (Just r)))
153getOnionReply 0x84 = OnionAnnounceResponse <$> get <*> get <*> get 156 maddr
154getOnionReply 0x86 = OnionToRouteResponse <$> getOnionAssym 157 Just (Right msg@(OnionToRouteResponse asym)) -> do
155 158 let ni = asymNodeInfo saddr asym
156replyAlias :: SockAddr -> OnionMessage Encrypted -> OnionDestination 159 return $ Left (msg, OnionDestination ni Nothing)
157replyAlias saddr (OnionAnnounceResponse _ _ _) 160 _ -> return right
158 = OnionDestination 161
159 $ either (error "replyAlias: bad protocol") id 162getOnionReply :: Word8 -> Maybe (Get (OnionMessage Encrypted))
160 $ nodeInfo zeroID saddr -- TODO OnionAnnounceResponse has no sender key 163getOnionReply 0x84 = Just $ OnionAnnounceResponse <$> get <*> get <*> get
161replyAlias saddr (OnionToRouteResponse asym) 164getOnionReply 0x86 = Just $ OnionToRouteResponse <$> getOnionAssym
162 = OnionDestination $ asymNodeInfo saddr asym 165getOnionReply _ = Nothing
163 166
164putOnionMsg :: OnionMessage Encrypted -> Put 167putOnionMsg :: OnionMessage Encrypted -> Put
165putOnionMsg (OnionAnnounce a) = putOnionAssym 0x83 (return ()) a 168putOnionMsg (OnionAnnounce a) = putOnionAssym 0x83 (return ()) a
@@ -167,10 +170,18 @@ putOnionMsg (OnionToRoute pubkey a) = putOnionAssym 0x85 (putPublicKey
167putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x 170putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x
168putOnionMsg (OnionToRouteResponse a) = putOnionAssym 0x86 (return ()) a 171putOnionMsg (OnionToRouteResponse a) = putOnionAssym 0x86 (return ()) a
169 172
170encodeOnionAddr :: (OnionMessage Encrypted,OnionDestination) -> (ByteString, SockAddr) 173encodeOnionAddr :: (NodeInfo -> r -> IO (Maybe OnionRoute))
171encodeOnionAddr (msg,OnionToOwner ni p) = ( runPut $ putResponse (OnionResponse p msg) 174 -> (OnionMessage Encrypted,OnionDestination r)
172 , nodeAddr ni ) 175 -> IO (Maybe (ByteString, SockAddr))
173encodeOnionAddr (msg,OnionDestination a) = ( runPut (putOnionMsg msg), nodeAddr a) -- TODO: Construct (OnionRequest N0)? 176encodeOnionAddr _ (msg,OnionToOwner ni p) =
177 return $ Just ( runPut $ putResponse (OnionResponse p msg)
178 , nodeAddr ni )
179encodeOnionAddr _ (msg,OnionDestination _ Nothing ) = return Nothing
180encodeOnionAddr getRoute (msg,OnionDestination ni (Just rid)) = do
181 let go route = do
182 return (runPut $ putRequest $ wrapForRoute msg ni route, nodeAddr ni)
183 getRoute ni rid >>= mapM go
184
174 185
175forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport 186forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport
176forwardOnions crypto udp = udp { awaitMessage = forwardAwait crypto udp } 187forwardOnions crypto udp = udp { awaitMessage = forwardAwait crypto udp }
@@ -253,7 +264,8 @@ data OnionResponse n = OnionResponse
253deriving instance KnownNat (PeanoNat n) => Show (OnionResponse n) 264deriving instance KnownNat (PeanoNat n) => Show (OnionResponse n)
254 265
255instance ( Serialize (ReturnPath n) ) => Serialize (OnionResponse n) where 266instance ( Serialize (ReturnPath n) ) => Serialize (OnionResponse n) where
256 get = OnionResponse <$> get <*> (get >>= getOnionReply) 267 get = OnionResponse <$> get <*> (get >>= fromMaybe (fail "illegal onion forwarding")
268 . getOnionReply)
257 put (OnionResponse p m) = put p >> putOnionMsg m 269 put (OnionResponse p m) = put p >> putOnionMsg m
258 270
259 271
@@ -525,7 +537,7 @@ instance Sized OnionData where
525 -- should be treated as variable sized. 537 -- should be treated as variable sized.
526 VarSize f -> f dhtpk 538 VarSize f -> f dhtpk
527 539
528encrypt :: TransportCrypto -> OnionMessage Identity -> OnionDestination -> (OnionMessage Encrypted, OnionDestination) 540encrypt :: TransportCrypto -> OnionMessage Identity -> OnionDestination r -> (OnionMessage Encrypted, OnionDestination r)
529encrypt crypto msg rpath = ( transcode ( (. (runIdentity . either id assymData)) 541encrypt crypto msg rpath = ( transcode ( (. (runIdentity . either id assymData))
530 . encryptMessage skey okey) 542 . encryptMessage skey okey)
531 msg 543 msg
@@ -545,31 +557,78 @@ encryptMessage skey destKey n a = ToxCrypto.encrypt secret plain
545 secret = computeSharedSecret skey destKey n 557 secret = computeSharedSecret skey destKey n
546 plain = encodePlain a 558 plain = encodePlain a
547 559
548decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionDestination -> Either String (OnionMessage Identity, OnionDestination) 560decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionDestination r -> Either String (OnionMessage Identity, OnionDestination r)
549decrypt crypto msg addr = (, addr) <$> (sequenceMessage $ transcode (decryptMessage crypto) msg) 561decrypt crypto msg addr = do
562 msg <- sequenceMessage $ transcode (\n -> decryptMessage crypto n . left (senderkey addr)) msg
563 Right (msg, addr)
564
565senderkey :: OnionDestination r -> t -> (Maybe PublicKey, t)
566senderkey addr e = (onionKey addr, e)
550 567
551decryptMessage :: Serialize x => 568decryptMessage :: Serialize x =>
552 TransportCrypto 569 TransportCrypto
553 -> Nonce24 570 -> Nonce24
554 -> Either (Encrypted x) (Assym (Encrypted x)) 571 -> Either (Maybe PublicKey, Encrypted x)
572 (Assym (Encrypted x))
555 -> (Either String ∘ Identity) x 573 -> (Either String ∘ Identity) x
556decryptMessage crypto n (Right assymE) = plain $ ToxCrypto.decrypt secret e 574decryptMessage crypto n arg
575 | Just secret <- msecret = plain $ ToxCrypto.decrypt secret e
576 | otherwise = Composed $ Left "decryptMessage: Unknown sender"
557 where 577 where
558 secret = computeSharedSecret (transportSecret crypto) (senderKey assymE) n 578 msecret = do sender <- mkey
559 e = assymData assymE 579 Just $ computeSharedSecret (transportSecret crypto) sender n
560 plain = Composed . fmap Identity . (>>= decodePlain) 580 (mkey,e) = either id (Just . senderKey &&& assymData) arg
561decryptMessage crypto n (Left e) = _todo -- OnionAnnounceResponse has no sender key 581 plain = Composed . fmap Identity . (>>= decodePlain)
562 582
563 583
564sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f) 584sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f)
565sequenceMessage (OnionAnnounce a) = fmap OnionAnnounce $ sequenceA $ fmap uncomposed a 585sequenceMessage (OnionAnnounce a) = fmap OnionAnnounce $ sequenceA $ fmap uncomposed a
566sequenceMessage (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 <$> uncomposed dta 586sequenceMessage (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 <$> uncomposed dta
567sequenceMessage (OnionToRoute pub a) = pure $ OnionToRoute pub a 587sequenceMessage (OnionToRoute pub a) = pure $ OnionToRoute pub a
568sequenceMessage (OnionToRouteResponse a) = pure $ OnionToRouteResponse a 588sequenceMessage (OnionToRouteResponse a) = pure $ OnionToRouteResponse a
569 589
570transcode :: forall f g. (forall a. Serialize a => Nonce24 -> Either (f a) (Assym (f a)) -> g a) -> OnionMessage f -> OnionMessage g 590transcode :: forall f g. (forall a. Serialize a => Nonce24 -> Either (f a) (Assym (f a)) -> g a) -> OnionMessage f -> OnionMessage g
571transcode f (OnionAnnounce a) = OnionAnnounce $ a { assymData = f (assymNonce a) (Right a) } 591transcode f (OnionAnnounce a) = OnionAnnounce $ a { assymData = f (assymNonce a) (Right a) }
572transcode f (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 $ f n24 $ Left dta 592transcode f (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 $ f n24 $ Left dta
573transcode f (OnionToRoute pub a) = OnionToRoute pub a 593transcode f (OnionToRoute pub a) = OnionToRoute pub a
574transcode f (OnionToRouteResponse a) = OnionToRouteResponse a 594transcode f (OnionToRouteResponse a) = OnionToRouteResponse a
575 595
596
597data OnionRoute = OnionRoute
598 { routeNonce :: Nonce24
599 , routeAliasA :: SecretKey
600 , routeAliasB :: SecretKey
601 , routeAliasC :: SecretKey
602 , routeNodeA :: NodeInfo
603 , routeNodeB :: NodeInfo
604 , routeNodeC :: NodeInfo
605 }
606
607wrapForRoute :: OnionMessage Encrypted -> NodeInfo -> OnionRoute -> OnionRequest N0
608wrapForRoute msg ni r = OnionRequest
609 { onionNonce = routeNonce r
610 , onionForward = wrapOnion (routeAliasA r)
611 (routeNonce r)
612 (id2key . nodeId $ routeNodeA r)
613 (nodeAddr $ routeNodeB r)
614 $ wrapOnion (routeAliasB r)
615 (routeNonce r)
616 (id2key . nodeId $ routeNodeB r)
617 (nodeAddr $ routeNodeC r)
618 $ wrapOnion (routeAliasC r)
619 (routeNonce r)
620 (id2key . nodeId $ routeNodeC r)
621 (nodeAddr ni)
622 $ NotForwarded msg
623 , pathFromOwner = NoReturnPath
624 }
625
626wrapOnion :: Serialize (Forwarding n msg) =>
627 SecretKey
628 -> Nonce24
629 -> PublicKey
630 -> SockAddr
631 -> Forwarding n msg
632 -> Forwarding (S n) msg
633wrapOnion skey nonce destkey saddr fwd =
634 Forwarding (toPublic skey) $ encryptMessage skey destkey nonce (Addressed saddr fwd)