summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-09-08 04:31:03 -0400
committerJoe Crayne <joe@jerkface.net>2018-09-08 04:41:04 -0400
commite5add92a477060d9bba10de7b980c89c24012691 (patch)
tree8a7508a0ad55339ce6dac9a31f593f2dd776ee41
parent55c5a979b3b25e1b7a13b1361c5f9cf1222f1653 (diff)
HandshakeCache remembers sent handshake data.
-rw-r--r--HandshakeCache.hs130
1 files changed, 130 insertions, 0 deletions
diff --git a/HandshakeCache.hs b/HandshakeCache.hs
new file mode 100644
index 00000000..6f9d466f
--- /dev/null
+++ b/HandshakeCache.hs
@@ -0,0 +1,130 @@
1module HandshakeCache where
2
3import Control.Concurrent.STM
4import Control.Monad
5import Data.Functor.Identity
6import qualified Data.Map.Strict as Map
7 ;import Data.Map.Strict (Map)
8import Data.Time.Clock.POSIX
9import Network.Socket
10import Data.Bool
11
12import Crypto.Hash
13
14import Crypto.Tox
15import qualified Data.MinMaxPSQ as MM
16 ;import Data.MinMaxPSQ (MinMaxPSQ')
17import DPut
18import Network.Tox.Crypto.Transport (Handshake, HandshakeData (..))
19import Network.Tox.DHT.Handlers (createCookieSTM)
20import Network.Tox.DHT.Transport (Cookie (..), CookieData (..), NodeInfo,
21 key2id, nodeInfo)
22import Network.Tox.Handshake
23
24data HandshakeCache = HandshakeCache
25 { -- Note that currently we are storing sent handshakes keyed by the
26 -- remotely issued cookie. This probably means that it's possible for
27 -- one your contacts that you are trying to open a session with to
28 -- prevent you from opening a session with another contact if they know
29 -- the cookie that person issued you.
30 hscTable :: TVar (MinMaxPSQ' (Cookie Encrypted) POSIXTime (SecretKey,HandshakeData))
31 , hscSend :: SockAddr -> Handshake Encrypted -> IO ()
32 , hscCrypto :: TransportCrypto
33 , hscPendingCookies :: TVar (Map (PublicKey,PublicKey) ())
34 }
35
36
37newHandshakeCache :: TransportCrypto -> (SockAddr -> Handshake Encrypted -> IO ()) -> IO HandshakeCache
38newHandshakeCache crypto send = atomically $ do
39 tbl <- newTVar MM.empty
40 pcs <- newTVar Map.empty
41 return HandshakeCache
42 { hscTable = tbl
43 , hscSend = send
44 , hscCrypto = crypto
45 , hscPendingCookies = pcs
46 }
47
48getSentHandshake :: HandshakeCache
49 -> SecretKey
50 -> SockAddr
51 -> Cookie Identity -- locally issued
52 -> Cookie Encrypted -- remotely issued
53 -> IO (Maybe (SecretKey, HandshakeData))
54getSentHandshake hscache me their_addr (Cookie _ (Identity cd)) ecookie = do
55 now <- getPOSIXTime
56 io <- atomically $ do
57 m <- checkExpiry now . MM.lookup' ecookie <$> readTVar (hscTable hscache)
58 case m of
59 Just s -> return $ return $ Just s
60 Nothing -> do
61 let them = longTermKey cd
62 case nodeInfo (key2id $ dhtKey cd) their_addr of
63 Left _ -> return $ return Nothing -- Non-internet address.
64 Right their_node -> do
65 (s,hs) <- cacheHandshakeSTM hscache me them their_node ecookie now
66 return $ do
67 hscSend hscache their_addr hs
68 return $ Just s
69 io
70
71
72checkExpiry :: POSIXTime -> Maybe (POSIXTime,r) -> Maybe r
73checkExpiry now m = do
74 (tm,s) <- m
75 guard $ tm + 5 {- seconds -} > now
76 return s
77
78hashCookie :: HashAlgorithm a => Cookie Encrypted -> Digest a
79hashCookie (Cookie n24 encrypted)
80 = hashFinalize $ hashUpdate (hashUpdate hashInit n24) encrypted
81
82cacheHandshakeSTM :: HandshakeCache
83 -> SecretKey -- ^ my ToxID key
84 -> PublicKey -- ^ them
85 -> NodeInfo -- ^ their DHT node
86 -> Cookie Encrypted -- ^ issued to me by them
87 -> POSIXTime -- ^ current time
88 -> STM ((SecretKey,HandshakeData), Handshake Encrypted)
89cacheHandshakeSTM hscache me them their_node ecookie timestamp = do
90 newsession <- transportNewKey (hscCrypto hscache)
91 freshCookie <- createCookieSTM timestamp (hscCrypto hscache) their_node them
92 n24 <- transportNewNonce (hscCrypto hscache)
93 let hsdata = HandshakeData
94 { baseNonce = n24
95 , sessionKey = toPublic newsession
96 , cookieHash = hashCookie ecookie
97 , otherCookie = freshCookie
98 }
99 hs <- encodeHandshake timestamp (hscCrypto hscache) me them ecookie hsdata
100 modifyTVar' (hscTable hscache) $ MM.insertTake' 20 ecookie (newsession,hsdata) timestamp
101 return ((newsession,hsdata),hs)
102
103cacheHandshake :: HandshakeCache
104 -> SecretKey
105 -> PublicKey
106 -> NodeInfo
107 -> Cookie Encrypted
108 -> IO (Handshake Encrypted)
109cacheHandshake hscache me them their_node ecookie = do
110 timestamp <- getPOSIXTime
111 dput XNetCrypto $ "cacheHandshake " ++ show (key2id them,ecookie)
112 atomically $ snd <$> cacheHandshakeSTM hscache me them their_node ecookie timestamp
113
114haveCachedCookie :: HandshakeCache
115 -> PublicKey
116 -> PublicKey
117 -> STM Bool
118haveCachedCookie hscache me them = do
119 m <- Map.lookup (me,them) <$> readTVar (hscPendingCookies hscache)
120 return $ maybe True (const False) m
121
122
123setPendingCookie :: HandshakeCache
124 -> PublicKey
125 -> PublicKey
126 -> Bool
127 -> STM ()
128setPendingCookie hscache me them pending = do
129 modifyTVar' (hscPendingCookies hscache) $ Map.alter (const $ bool Nothing (Just ()) pending)
130 (me,them)