diff options
Diffstat (limited to 'src/Network')
-rw-r--r-- | src/Network/Tox/Crypto/Handlers.hs | 275 |
1 files changed, 183 insertions, 92 deletions
diff --git a/src/Network/Tox/Crypto/Handlers.hs b/src/Network/Tox/Crypto/Handlers.hs index 2f8b059a..bcca65e6 100644 --- a/src/Network/Tox/Crypto/Handlers.hs +++ b/src/Network/Tox/Crypto/Handlers.hs | |||
@@ -1,6 +1,7 @@ | |||
1 | {-# LANGUAGE NamedFieldPuns #-} | 1 | {-# LANGUAGE NamedFieldPuns #-} |
2 | {-# LANGUAGE TupleSections #-} | 2 | {-# LANGUAGE TupleSections #-} |
3 | {-# LANGUAGE TypeOperators #-} | 3 | {-# LANGUAGE TypeOperators #-} |
4 | {-# LANGUAGE DeriveFunctor #-} | ||
4 | module Network.Tox.Crypto.Handlers where | 5 | module Network.Tox.Crypto.Handlers where |
5 | 6 | ||
6 | import Network.QueryResponse | 7 | import Network.QueryResponse |
@@ -50,23 +51,72 @@ import Debug.Trace | |||
50 | import Text.Printf | 51 | import Text.Printf |
51 | import Data.Bool | 52 | import Data.Bool |
52 | 53 | ||
54 | |||
55 | -- * These types are isomorphic to Maybe, but have the advantage of documenting | ||
56 | -- when an item is expected to become known. | ||
57 | data UponDHTKey a = NeedDHTKey | HaveDHTKey a deriving (Functor,Show,Eq) | ||
58 | data UponCookie a = NeedCookie | HaveCookie a deriving (Functor,Show,Eq) | ||
59 | data UponHandshake a = NeedHandshake | HaveHandshake a deriving (Functor,Show,Eq) | ||
60 | data UponCryptoPacket a = NeedCryptoPacket | HaveCryptoPacket a deriving (Functor,Show,Eq) | ||
61 | |||
53 | -- util, todo: move to another module | 62 | -- util, todo: move to another module |
54 | maybeToEither :: Maybe b -> Either String b | 63 | maybeToEither :: AsMaybe f => f b -> Either String b |
55 | maybeToEither (Just x) = Right x | 64 | maybeToEither y | Just x <- toMaybe y = Right x |
56 | maybeToEither Nothing = Left "maybeToEither" | 65 | maybeToEither _ = Left "maybeToEither" |
66 | |||
67 | -- | type class encoding of isomorphism to Maybe | ||
68 | class AsMaybe f where | ||
69 | toMaybe :: f a -> Maybe a | ||
70 | -- | The o in from is left out so as not to colide with 'Data.Maybe.fromMaybe' | ||
71 | frmMaybe :: Maybe a -> f a | ||
72 | |||
73 | instance AsMaybe Maybe where | ||
74 | toMaybe x = x | ||
75 | frmMaybe x = x | ||
76 | |||
77 | instance AsMaybe UponDHTKey where | ||
78 | toMaybe NeedDHTKey = Nothing | ||
79 | toMaybe (HaveDHTKey x) = Just x | ||
80 | frmMaybe Nothing = NeedDHTKey | ||
81 | frmMaybe (Just x) = HaveDHTKey x | ||
82 | |||
83 | instance AsMaybe UponCookie where | ||
84 | toMaybe NeedCookie = Nothing | ||
85 | toMaybe (HaveCookie x) = Just x | ||
86 | frmMaybe Nothing = NeedCookie | ||
87 | frmMaybe (Just x) = HaveCookie x | ||
88 | |||
89 | instance AsMaybe UponHandshake where | ||
90 | toMaybe NeedHandshake = Nothing | ||
91 | toMaybe (HaveHandshake x) = Just x | ||
92 | frmMaybe Nothing = NeedHandshake | ||
93 | frmMaybe (Just x) = HaveHandshake x | ||
94 | |||
95 | instance AsMaybe UponCryptoPacket where | ||
96 | toMaybe NeedCryptoPacket = Nothing | ||
97 | toMaybe (HaveCryptoPacket x) = Just x | ||
98 | frmMaybe Nothing = NeedCryptoPacket | ||
99 | frmMaybe (Just x) = HaveCryptoPacket x | ||
100 | |||
57 | 101 | ||
58 | data NetCryptoSessionStatus = Unaccepted | Accepted {- InProgress AwaitingSessionPacket -} | Confirmed {- Established -} | 102 | data NetCryptoSessionStatus = Unaccepted | Accepted {- InProgress AwaitingSessionPacket -} | Confirmed {- Established -} |
59 | deriving (Eq,Ord,Show,Enum) | 103 | deriving (Eq,Ord,Show,Enum) |
60 | 104 | ||
61 | 105 | ||
106 | -- | The idea of IOHook is to replicate the familiar pattern | ||
107 | -- where a function returns Nothing to consume a value | ||
108 | -- or a function used to modify the value and pass it | ||
109 | -- to be processed by another hook. | ||
62 | type IOHook addr x = addr -> x -> IO (Maybe (x -> x)) | 110 | type IOHook addr x = addr -> x -> IO (Maybe (x -> x)) |
111 | |||
112 | -- | NetCryptoHook's use the Session as their 'addr' and the | ||
113 | -- value they consume or modify is CryptoMessage. | ||
63 | type NetCryptoHook = IOHook NetCryptoSession CryptoMessage | 114 | type NetCryptoHook = IOHook NetCryptoSession CryptoMessage |
115 | |||
116 | -- | Convert an id byte to it's type (in Word64 format) | ||
117 | -- Although the type doesn't enforce it, MsgTypeArray | ||
118 | -- should always have 256 entries. | ||
64 | type MsgTypeArray = A.UArray Word8 Word64 | 119 | type MsgTypeArray = A.UArray Word8 Word64 |
65 | -- type MsgOutMap = RangeMap STArray Word8 STRef | ||
66 | -- type MsgOutMap = W64.Word64Map Word8 | ||
67 | -- type MsgOutMap = A.UArray Word64 Word8 -- if above is too slow, switch to this, but use reasonable bounds | ||
68 | -- msgOutMapLookup :: Word64 -> MsgOutMap -> STM (Maybe Word8) | ||
69 | -- msgOutMapLookup k mp = return (W64.lookup k mp) | ||
70 | 120 | ||
71 | -- | Information, that may be made visible in multiple sessions, as well | 121 | -- | Information, that may be made visible in multiple sessions, as well |
72 | -- as displayed in some way to the user via mutiple views. | 122 | -- as displayed in some way to the user via mutiple views. |
@@ -168,36 +218,65 @@ data NetCryptoSession = NCrypto | |||
168 | , ncMyPublicKey :: PublicKey | 218 | , ncMyPublicKey :: PublicKey |
169 | , ncSessionId :: SessionID | 219 | , ncSessionId :: SessionID |
170 | , ncTheirPublicKey :: PublicKey -- Tox id w/o nospam | 220 | , ncTheirPublicKey :: PublicKey -- Tox id w/o nospam |
171 | , ncTheirBaseNonce :: TVar Nonce24 -- base nonce + packet number | 221 | , ncTheirBaseNonce :: TVar (UponHandshake Nonce24) -- base nonce + packet number |
172 | , ncMyPacketNonce :: TVar Nonce24 -- base nonce + packet number | 222 | , ncMyPacketNonce :: TVar Nonce24 -- base nonce + packet number |
173 | , ncHandShake :: TVar (Maybe (Handshake Encrypted)) | 223 | , ncHandShake :: TVar (UponHandshake (Handshake Encrypted)) |
174 | , ncCookie :: TVar (Maybe Cookie) -- ^ Cookie issued by remote peer | 224 | , ncCookie :: TVar (UponCookie Cookie) -- ^ Cookie issued by remote peer |
175 | , ncTheirDHTKey :: PublicKey | 225 | , ncTheirDHTKey :: UponDHTKey PublicKey |
176 | , ncTheirSessionPublic :: Maybe PublicKey | 226 | , ncTheirSessionPublic :: UponHandshake PublicKey |
177 | , ncSessionSecret :: SecretKey | 227 | , ncSessionSecret :: SecretKey |
178 | , ncSockAddr :: SockAddr | 228 | , ncSockAddr :: UponDHTKey SockAddr |
229 | -- The remaining fields correspond to implementation specific state -- | ||
230 | -- where as the prior fields will be used in any implementation -- | ||
179 | , ncHooks :: TVar (Map.Map MessageType [NetCryptoHook]) | 231 | , ncHooks :: TVar (Map.Map MessageType [NetCryptoHook]) |
180 | , ncUnrecognizedHook :: TVar (MessageType -> NetCryptoHook) | 232 | , ncUnrecognizedHook :: TVar (MessageType -> NetCryptoHook) |
181 | , ncIncomingTypeArray :: TVar MsgTypeArray -- ^ supported messages, 0 for unsupported, | 233 | , ncIncomingTypeArray :: TVar MsgTypeArray |
182 | -- otherwise the messageType, some message types | 234 | -- ^ This array maps 255 Id bytes to MessageType |
183 | -- may not be in ncHooks yet, but they should appear | 235 | -- It should contain all messages this session understands. |
184 | -- here if ncUnrecognizedHook will add them to ncHooks | 236 | -- Use 0 for unsupported. It is used when a message comes |
185 | -- on an as-need basis. | 237 | -- in, and should ordinarily be the identity map. |
238 | -- | ||
239 | -- Id's 0xC7 and 0x63 should contain range-specifying types only, if | ||
240 | -- such things come to be defined, because these MessageId's are | ||
241 | -- always escapes. | ||
242 | -- | ||
243 | -- Currently, the values at these indices are ignored. | ||
186 | , ncOutgoingIdMap :: RangeMap TArray Word8 TVar | 244 | , ncOutgoingIdMap :: RangeMap TArray Word8 TVar |
187 | -- ^ used to lookup the outgoing id for a type, for now always an identity map | 245 | -- ^ used to lookup the outgoing id for a type when sending an outoing message |
188 | -- TODO: need 2 more outgoing id maps for escape-lossy and escape-lossless (group msgs) | 246 | , ncOutgoingIdMapEscapedLossy :: TVar (A.Array Word8 Word8) |
189 | , ncAllSessions :: NetCryptoSessions -- ^ may be needed if one net-crypto session | 247 | -- ^ mapping of secondary id, when primary id is 0xC7 |
190 | -- needs to possibly start another, as is | 248 | -- (These Id's are called 'MessageName' in 'Network.Tox.Crypto.Transport') |
191 | -- the case in group chats | 249 | -- used when sending an outoing message |
250 | , ncOutgoingIdMapEscapedLossless :: TVar (A.Array Word8 Word8) | ||
251 | -- ^ mapping of secondary id, when primary id is 0x63 | ||
252 | -- (These Id's are called 'MessageName' in 'Network.Tox.Crypto.Transport') | ||
253 | -- used when sending an outoing message | ||
254 | , ncAllSessions :: NetCryptoSessions | ||
255 | -- ^ needed if one net-crypto session | ||
256 | -- needs to possibly start another, as is | ||
257 | -- the case in group chats | ||
192 | , ncView :: TVar SessionView | 258 | , ncView :: TVar SessionView |
259 | -- ^ contains your nick, status etc | ||
193 | , ncPacketQueue :: PacketQueue CryptoData | 260 | , ncPacketQueue :: PacketQueue CryptoData |
194 | , ncBufferStart :: TVar Word32 | 261 | -- ^ a buffer in which incoming packets may be stored out of order |
262 | -- but from which they may be extracted in sequence, | ||
263 | -- helps ensure lossless packets are processed in order | ||
195 | , ncDequeueThread :: Maybe ThreadId | 264 | , ncDequeueThread :: Maybe ThreadId |
265 | -- ^ when the thread which dequeues from ncPacketQueue | ||
266 | -- is started, its ThreadId is stored here | ||
196 | , ncPingMachine :: Maybe PingMachine | 267 | , ncPingMachine :: Maybe PingMachine |
197 | , ncOutgoingQueue :: PQ.PacketOutQueue (State,Nonce24,RangeMap TArray Word8 TVar) | 268 | -- ^ when the ping thread is started, store it here |
198 | CryptoMessage | 269 | , ncOutgoingQueue :: UponHandshake |
199 | (CryptoPacket Encrypted) | 270 | (PQ.PacketOutQueue |
200 | CryptoData | 271 | (State,Nonce24,RangeMap TArray Word8 TVar) |
272 | CryptoMessage | ||
273 | (CryptoPacket Encrypted) | ||
274 | CryptoData) | ||
275 | -- ^ To send a message add it to this queue, by calling 'tryAppendQueueOutgoing' | ||
276 | -- but remember to call 'readyOutGoing' first, because the shared secret cache | ||
277 | -- presently requires the IO monad. | ||
278 | -- This specialized queue handles setting buffer_start and buffer_end and encrypting | ||
279 | -- 'readyOutGoing' provides the first parameter to 'tryAppendQueueOutgoing' | ||
201 | , ncLastNMsgs :: CyclicBuffer (Bool{-Handled?-},(ViewSnapshot,InOrOut CryptoMessage)) | 280 | , ncLastNMsgs :: CyclicBuffer (Bool{-Handled?-},(ViewSnapshot,InOrOut CryptoMessage)) |
202 | -- ^ cyclic buffer, holds the last N non-handshake crypto messages | 281 | -- ^ cyclic buffer, holds the last N non-handshake crypto messages |
203 | -- even if there is no attached user interface. | 282 | -- even if there is no attached user interface. |
@@ -222,6 +301,7 @@ data NetCryptoSessions = NCSessions | |||
222 | , listenerIDSupply :: TVar Supply | 301 | , listenerIDSupply :: TVar Supply |
223 | } | 302 | } |
224 | 303 | ||
304 | -- | This is the type of a hook to run when a session is created. | ||
225 | type NewSessionHook = IOHook (Maybe NoSpam) NetCryptoSession | 305 | type NewSessionHook = IOHook (Maybe NoSpam) NetCryptoSession |
226 | 306 | ||
227 | addNewSessionHook :: NetCryptoSessions -> NewSessionHook -> STM () | 307 | addNewSessionHook :: NetCryptoSessions -> NewSessionHook -> STM () |
@@ -229,7 +309,7 @@ addNewSessionHook allsessions@(NCSessions { announceNewSessionHooks }) hook = mo | |||
229 | 309 | ||
230 | forgetCrypto :: TransportCrypto -> NetCryptoSessions -> NetCryptoSession -> STM () | 310 | forgetCrypto :: TransportCrypto -> NetCryptoSessions -> NetCryptoSession -> STM () |
231 | forgetCrypto crypto (NCSessions {netCryptoSessions,netCryptoSessionsByKey}) session = do | 311 | forgetCrypto crypto (NCSessions {netCryptoSessions,netCryptoSessionsByKey}) session = do |
232 | let addr = ncSockAddr session | 312 | let HaveDHTKey addr = ncSockAddr session |
233 | sid = ncSessionId session | 313 | sid = ncSessionId session |
234 | sPubKey = ncTheirPublicKey session | 314 | sPubKey = ncTheirPublicKey session |
235 | byAddrMap <- readTVar netCryptoSessions | 315 | byAddrMap <- readTVar netCryptoSessions |
@@ -305,7 +385,7 @@ data HandshakeParams | |||
305 | = HParam | 385 | = HParam |
306 | { hpTheirBaseNonce :: Maybe Nonce24 -- ignore and generate your own | 386 | { hpTheirBaseNonce :: Maybe Nonce24 -- ignore and generate your own |
307 | , hpOtherCookie :: Cookie | 387 | , hpOtherCookie :: Cookie |
308 | , hpTheirSessionKeyPublic :: PublicKey | 388 | , hpTheirSessionKeyPublic :: Maybe PublicKey |
309 | , hpMySecretKey :: SecretKey | 389 | , hpMySecretKey :: SecretKey |
310 | , hpCookieRemotePubkey :: PublicKey | 390 | , hpCookieRemotePubkey :: PublicKey |
311 | , hpCookieRemoteDhtkey :: PublicKey | 391 | , hpCookieRemoteDhtkey :: PublicKey |
@@ -409,9 +489,9 @@ freshCryptoSession :: NetCryptoSessions -> SockAddr -> HandshakeParams -> IO () | |||
409 | freshCryptoSession sessions | 489 | freshCryptoSession sessions |
410 | addr | 490 | addr |
411 | hp@(HParam | 491 | hp@(HParam |
412 | { hpTheirBaseNonce = Just theirBaseNonce | 492 | { hpTheirBaseNonce = mbtheirBaseNonce |
413 | , hpOtherCookie = otherCookie | 493 | , hpOtherCookie = otherCookie |
414 | , hpTheirSessionKeyPublic = theirSessionKey | 494 | , hpTheirSessionKeyPublic = mbtheirSessionKey |
415 | , hpMySecretKey = key | 495 | , hpMySecretKey = key |
416 | , hpCookieRemotePubkey = remotePublicKey | 496 | , hpCookieRemotePubkey = remotePublicKey |
417 | , hpCookieRemoteDhtkey = remoteDhtPublicKey | 497 | , hpCookieRemoteDhtkey = remoteDhtPublicKey |
@@ -424,7 +504,7 @@ freshCryptoSession sessions | |||
424 | modifyTVar (nextSessionId sessions) (+1) | 504 | modifyTVar (nextSessionId sessions) (+1) |
425 | return x | 505 | return x |
426 | ncState0 <- atomically $ newTVar Accepted -- (InProgress AwaitingSessionPacket) | 506 | ncState0 <- atomically $ newTVar Accepted -- (InProgress AwaitingSessionPacket) |
427 | ncTheirBaseNonce0 <- atomically $ newTVar theirBaseNonce | 507 | ncTheirBaseNonce0 <- atomically $ newTVar (frmMaybe mbtheirBaseNonce) |
428 | n24 <- atomically $ transportNewNonce crypto | 508 | n24 <- atomically $ transportNewNonce crypto |
429 | state <- lookupSharedSecret crypto key remotePublicKey n24 | 509 | state <- lookupSharedSecret crypto key remotePublicKey n24 |
430 | newBaseNonce <- atomically $ transportNewNonce crypto | 510 | newBaseNonce <- atomically $ transportNewNonce crypto |
@@ -437,17 +517,17 @@ freshCryptoSession sessions | |||
437 | , handshakeData = encrypted | 517 | , handshakeData = encrypted |
438 | } | 518 | } |
439 | let myhandshake= encodeHandshake <$> mbMyhandshakeData | 519 | let myhandshake= encodeHandshake <$> mbMyhandshakeData |
440 | ncHandShake0 <- atomically $ newTVar myhandshake | 520 | ncHandShake0 <- atomically $ newTVar (frmMaybe myhandshake) |
441 | forM myhandshake $ \response_handshake -> do | 521 | forM myhandshake $ \response_handshake -> do |
442 | sendMessage (sessionTransport sessions) addr (NetHandshake response_handshake) | 522 | sendMessage (sessionTransport sessions) addr (NetHandshake response_handshake) |
443 | ncMyPacketNonce0 <- atomically $ newTVar newBaseNonce | 523 | ncMyPacketNonce0 <- atomically $ newTVar newBaseNonce |
444 | cookie0 <- atomically $ newTVar (Just otherCookie) | 524 | cookie0 <- atomically $ newTVar (HaveCookie otherCookie) |
445 | newsession <- generateSecretKey | 525 | newsession <- generateSecretKey |
446 | ncHooks0 <- atomically $ newTVar (defaultHooks sessions) | 526 | ncHooks0 <- atomically $ newTVar (defaultHooks sessions) |
447 | ncUnrecognizedHook0 <- atomically $ newTVar (defaultUnrecognizedHook sessions) | 527 | ncUnrecognizedHook0 <- atomically $ newTVar (defaultUnrecognizedHook sessions) |
448 | ncIncomingTypeArray0 <- atomically $ newTVar (msgTypeArray sessions) | 528 | ncIncomingTypeArray0 <- atomically $ newTVar (msgTypeArray sessions) |
449 | let idMap = foldl (\mp (x,y) -> W64.insert x y mp) W64.empty (zip [0..255] [0..255]) | 529 | let idMap = foldl (\mp (x,y) -> W64.insert x y mp) W64.empty (zip [0..255] [0..255]) |
450 | ncOutgoingIdMap0 <- atomically $ do | 530 | (ncOutgoingIdMap0,lossyEscapeIdMap,losslessEscapeIdMap) <- atomically $ do |
451 | idmap <- emptySTMRangeMap | 531 | idmap <- emptySTMRangeMap |
452 | insertArrayAt idmap 0 (A.listArray (0,255) [0 .. 255]) | 532 | insertArrayAt idmap 0 (A.listArray (0,255) [0 .. 255]) |
453 | -- the 2 escape ranges are adjacent, so put them in one array: | 533 | -- the 2 escape ranges are adjacent, so put them in one array: |
@@ -456,18 +536,25 @@ freshCryptoSession sessions | |||
456 | )) | 536 | )) |
457 | -- lossless as separate range could have been done: | 537 | -- lossless as separate range could have been done: |
458 | -- > insertArrayAt idmap 768 (A.listArray (768,1023) (replicate 256 0x63)) | 538 | -- > insertArrayAt idmap 768 (A.listArray (768,1023) (replicate 256 0x63)) |
459 | return idmap | 539 | lossyEsc <- newTVar $ A.listArray (0,255) [0 .. 255] |
540 | losslessEsc <- newTVar $ A.listArray (0,255) [0 .. 255] | ||
541 | return (idmap,lossyEsc,losslessEsc) | ||
460 | ncView0 <- atomically $ newTVar (sessionView sessions) | 542 | ncView0 <- atomically $ newTVar (sessionView sessions) |
461 | pktq <- atomically $ PQ.new (inboundQueueCapacity sessions) 0 | 543 | pktq <- atomically $ PQ.new (inboundQueueCapacity sessions) 0 |
462 | bufstart <- atomically $ newTVar 0 | 544 | bufstart <- atomically $ newTVar 0 |
463 | let toWireIO = do | 545 | mbpktoq |
464 | f <- lookupNonceFunction crypto newsession theirSessionKey | 546 | <- case mbtheirSessionKey of |
465 | atomically $ do | 547 | Nothing -> return NeedHandshake |
466 | n24 <- readTVar ncMyPacketNonce0 | 548 | Just theirSessionKey -> do |
467 | let n24plus1 = incrementNonce24 n24 | 549 | let toWireIO = do |
468 | writeTVar ncMyPacketNonce0 n24plus1 | 550 | f <- lookupNonceFunction crypto newsession theirSessionKey |
469 | return (return (f n24, n24, ncOutgoingIdMap0)) | 551 | atomically $ do |
470 | pktoq <- atomically $ PQ.newOutGoing pktq ncToWire toWireIO 0 (outboundQueueCapacity sessions) 0 | 552 | n24 <- readTVar ncMyPacketNonce0 |
553 | let n24plus1 = incrementNonce24 n24 | ||
554 | writeTVar ncMyPacketNonce0 n24plus1 | ||
555 | return (return (f n24, n24, ncOutgoingIdMap0)) | ||
556 | pktoq <- atomically $ PQ.newOutGoing pktq ncToWire toWireIO 0 (outboundQueueCapacity sessions) 0 | ||
557 | return (HaveHandshake pktoq) | ||
471 | lastNQ <- atomically (CB.new 10 0 :: STM (CyclicBuffer (Bool,(ViewSnapshot,InOrOut CryptoMessage)))) | 558 | lastNQ <- atomically (CB.new 10 0 :: STM (CyclicBuffer (Bool,(ViewSnapshot,InOrOut CryptoMessage)))) |
472 | listeners <- atomically $ newTVar IntMap.empty | 559 | listeners <- atomically $ newTVar IntMap.empty |
473 | msgNum <- atomically $ newTVar 0 | 560 | msgNum <- atomically $ newTVar 0 |
@@ -481,21 +568,22 @@ freshCryptoSession sessions | |||
481 | , ncMyPacketNonce = ncMyPacketNonce0 | 568 | , ncMyPacketNonce = ncMyPacketNonce0 |
482 | , ncHandShake = ncHandShake0 | 569 | , ncHandShake = ncHandShake0 |
483 | , ncCookie = cookie0 | 570 | , ncCookie = cookie0 |
484 | , ncTheirDHTKey = remoteDhtPublicKey | 571 | , ncTheirDHTKey = HaveDHTKey remoteDhtPublicKey |
485 | , ncTheirSessionPublic = Just theirSessionKey | 572 | , ncTheirSessionPublic = frmMaybe mbtheirSessionKey |
486 | , ncSessionSecret = newsession | 573 | , ncSessionSecret = newsession |
487 | , ncSockAddr = addr | 574 | , ncSockAddr = HaveDHTKey addr |
488 | , ncHooks = ncHooks0 | 575 | , ncHooks = ncHooks0 |
489 | , ncUnrecognizedHook = ncUnrecognizedHook0 | 576 | , ncUnrecognizedHook = ncUnrecognizedHook0 |
490 | , ncAllSessions = sessions | 577 | , ncAllSessions = sessions |
491 | , ncIncomingTypeArray = ncIncomingTypeArray0 | 578 | , ncIncomingTypeArray = ncIncomingTypeArray0 |
492 | , ncOutgoingIdMap = ncOutgoingIdMap0 | 579 | , ncOutgoingIdMap = ncOutgoingIdMap0 |
580 | , ncOutgoingIdMapEscapedLossy = lossyEscapeIdMap | ||
581 | , ncOutgoingIdMapEscapedLossless = losslessEscapeIdMap | ||
493 | , ncView = ncView0 | 582 | , ncView = ncView0 |
494 | , ncPacketQueue = pktq | 583 | , ncPacketQueue = pktq |
495 | , ncBufferStart = bufstart | ||
496 | , ncDequeueThread = Nothing -- error "you want the NetCrypto-Dequeue thread id, but is it started?" | 584 | , ncDequeueThread = Nothing -- error "you want the NetCrypto-Dequeue thread id, but is it started?" |
497 | , ncPingMachine = Nothing -- error "you want the NetCrypto-PingMachine, but is it started?" | 585 | , ncPingMachine = Nothing -- error "you want the NetCrypto-PingMachine, but is it started?" |
498 | , ncOutgoingQueue = pktoq | 586 | , ncOutgoingQueue = mbpktoq |
499 | , ncLastNMsgs = lastNQ | 587 | , ncLastNMsgs = lastNQ |
500 | , ncListeners = listeners | 588 | , ncListeners = listeners |
501 | } | 589 | } |
@@ -507,37 +595,40 @@ freshCryptoSession sessions | |||
507 | cd <- atomically $ PQ.dequeue pktq | 595 | cd <- atomically $ PQ.dequeue pktq |
508 | _ <- runCryptoHook (netCryptoSession0 {ncDequeueThread=Just tid}) (bufferData cd) | 596 | _ <- runCryptoHook (netCryptoSession0 {ncDequeueThread=Just tid}) (bufferData cd) |
509 | loop | 597 | loop |
510 | -- launch dequeueOutgoing thread | 598 | case mbpktoq of |
511 | threadidOutgoing <- forkIO $ do | 599 | NeedHandshake -> return () |
512 | tid <- myThreadId | 600 | HaveHandshake pktoq -> do |
513 | labelThread tid ("NetCryptoDequeueOutgoing." ++ show (key2id remotePublicKey)) | 601 | -- launch dequeueOutgoing thread |
514 | fix $ \loop -> do | 602 | threadidOutgoing <- forkIO $ do |
515 | (_,pkt) <- atomically $ PQ.dequeueOutgoing pktoq | 603 | tid <- myThreadId |
516 | dput XNetCrypto "NetCryptoDequeueOutgoing thread... Sending encrypted Packet" | 604 | labelThread tid ("NetCryptoDequeueOutgoing." ++ show (key2id remotePublicKey)) |
517 | sendMessage (sessionTransport sessions) addr (NetCrypto pkt) | 605 | fix $ \loop -> do |
518 | loop | 606 | (_,pkt) <- atomically $ PQ.dequeueOutgoing pktoq |
519 | -- launch ping thread | 607 | dput XNetCrypto "NetCryptoDequeueOutgoing thread... Sending encrypted Packet" |
520 | fuzz <- randomRIO (0,2000) | 608 | sendMessage (sessionTransport sessions) addr (NetCrypto pkt) |
521 | pingMachine <- forkPingMachine ("NetCrypto." ++ show (key2id remotePublicKey)) (15000 + fuzz) 2000 | 609 | loop |
522 | -- update session with thread ids | 610 | -- launch ping thread |
523 | let netCryptoSession = netCryptoSession0 {ncDequeueThread=Just threadid, ncPingMachine=Just pingMachine} | 611 | fuzz <- randomRIO (0,2000) |
524 | -- add this session to the lookup maps | 612 | pingMachine <- forkPingMachine ("NetCrypto." ++ show (key2id remotePublicKey)) (15000 + fuzz) 2000 |
525 | atomically $ do | 613 | -- update session with thread ids |
526 | modifyTVar allsessions (Map.insert addr netCryptoSession) | 614 | let netCryptoSession = netCryptoSession0 {ncDequeueThread=Just threadid, ncPingMachine=Just pingMachine} |
527 | byKeyResult <- readTVar allsessionsByKey >>= return . Map.lookup remotePublicKey | 615 | -- add this session to the lookup maps |
528 | case byKeyResult of | 616 | atomically $ do |
529 | Nothing -> modifyTVar allsessionsByKey (Map.insert remotePublicKey [netCryptoSession]) | 617 | modifyTVar allsessions (Map.insert addr netCryptoSession) |
530 | Just xs -> modifyTVar allsessionsByKey (Map.insert remotePublicKey (netCryptoSession:xs)) | 618 | byKeyResult <- readTVar allsessionsByKey >>= return . Map.lookup remotePublicKey |
531 | -- run announceNewSessionHooks | 619 | case byKeyResult of |
532 | hooks <- atomically $ readTVar (announceNewSessionHooks sessions) | 620 | Nothing -> modifyTVar allsessionsByKey (Map.insert remotePublicKey [netCryptoSession]) |
533 | flip fix (hooks,netCryptoSession) $ \loop (hooks,session) -> | 621 | Just xs -> modifyTVar allsessionsByKey (Map.insert remotePublicKey (netCryptoSession:xs)) |
534 | case hooks of | 622 | -- run announceNewSessionHooks |
535 | [] -> return () | 623 | hooks <- atomically $ readTVar (announceNewSessionHooks sessions) |
536 | (h:hs) -> do | 624 | flip fix (hooks,netCryptoSession) $ \loop (hooks,session) -> |
537 | r <- h Nothing session | 625 | case hooks of |
538 | case r of | 626 | [] -> return () |
539 | Just f -> loop (hs, f session) | 627 | (h:hs) -> do |
540 | Nothing -> return () | 628 | r <- h Nothing session |
629 | case r of | ||
630 | Just f -> loop (hs, f session) | ||
631 | Nothing -> return () | ||
541 | 632 | ||
542 | -- | Called when we get a handshake, but there's already a session entry. | 633 | -- | Called when we get a handshake, but there's already a session entry. |
543 | updateCryptoSession :: NetCryptoSessions -> SockAddr -> HandshakeParams -> NetCryptoSession -> IO () | 634 | updateCryptoSession :: NetCryptoSessions -> SockAddr -> HandshakeParams -> NetCryptoSession -> IO () |
@@ -554,21 +645,21 @@ updateCryptoSession sessions addr hp session = do | |||
554 | then do | 645 | then do |
555 | dput XNetCrypto "updateCryptoSession already accepted.." | 646 | dput XNetCrypto "updateCryptoSession already accepted.." |
556 | dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0 | 647 | dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0 |
557 | ++ bool "(/=)" "(==)" (Just ncTheirBaseNonce0 == hpTheirBaseNonce hp) | 648 | ++ bool "(/=)" "(==)" (toMaybe ncTheirBaseNonce0 == hpTheirBaseNonce hp) |
558 | ++ "hpTheirBaseNonce=" ++ show (hpTheirBaseNonce hp)) | 649 | ++ "hpTheirBaseNonce=" ++ show (hpTheirBaseNonce hp)) |
559 | dput XNetCrypto (" ncTheirDHTKey=" ++ show (ncTheirDHTKey session) | 650 | dput XNetCrypto (" ncTheirDHTKey=" ++ show (ncTheirDHTKey session) |
560 | ++ bool "{/=}" "{==}" (ncTheirDHTKey session == hpCookieRemoteDhtkey hp) | 651 | ++ bool "{/=}" "{==}" (ncTheirDHTKey session == HaveDHTKey (hpCookieRemoteDhtkey hp)) |
561 | ++ "hpCookieRemoteDhtkey=" ++ show (hpCookieRemoteDhtkey hp)) | 652 | ++ "hpCookieRemoteDhtkey=" ++ show (hpCookieRemoteDhtkey hp)) |
562 | when ( -- Just ncTheirBaseNonce0 /= hpTheirBaseNonce hp -- XXX: Do we really want to compare base nonce here? | 653 | when ( -- Just ncTheirBaseNonce0 /= hpTheirBaseNonce hp -- XXX: Do we really want to compare base nonce here? |
563 | -- || | 654 | -- || |
564 | ncTheirDHTKey session /= hpCookieRemoteDhtkey hp | 655 | ncTheirDHTKey session /= HaveDHTKey (hpCookieRemoteDhtkey hp) |
565 | ) $ freshCryptoSession sessions addr hp | 656 | ) $ freshCryptoSession sessions addr hp |
566 | else do | 657 | else do |
567 | dput XNetCrypto "updateCryptoSession else clause" | 658 | dput XNetCrypto "updateCryptoSession else clause" |
568 | dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0 | 659 | dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0 |
569 | ++ bool "(/=)" "(==)" (Just ncTheirBaseNonce0 == hpTheirBaseNonce hp) | 660 | ++ bool "(/=)" "(==)" (toMaybe ncTheirBaseNonce0 == hpTheirBaseNonce hp) |
570 | ++ "hpTheirBaseNonce=" ++ show (hpTheirBaseNonce hp)) | 661 | ++ "hpTheirBaseNonce=" ++ show (hpTheirBaseNonce hp)) |
571 | if ( Just ncTheirBaseNonce0 /= hpTheirBaseNonce hp) | 662 | if ( ncTheirBaseNonce0 /= frmMaybe (hpTheirBaseNonce hp)) |
572 | then freshCryptoSession sessions addr hp -- basenonce mismatch, trigger refresh | 663 | then freshCryptoSession sessions addr hp -- basenonce mismatch, trigger refresh |
573 | else atomically $ writeTVar (ncState session) Accepted -- (InProgress AwaitingSessionPacket) | 664 | else atomically $ writeTVar (ncState session) Accepted -- (InProgress AwaitingSessionPacket) |
574 | 665 | ||
@@ -622,7 +713,7 @@ cryptoNetHandler sessions addr (NetHandshake (Handshake (Cookie n24 ecookie) non | |||
622 | HParam | 713 | HParam |
623 | { hpTheirBaseNonce = Just baseNonce | 714 | { hpTheirBaseNonce = Just baseNonce |
624 | , hpOtherCookie = otherCookie | 715 | , hpOtherCookie = otherCookie |
625 | , hpTheirSessionKeyPublic = sessionKey | 716 | , hpTheirSessionKeyPublic = Just sessionKey |
626 | , hpMySecretKey = key | 717 | , hpMySecretKey = key |
627 | , hpCookieRemotePubkey = remotePubkey | 718 | , hpCookieRemotePubkey = remotePubkey |
628 | , hpCookieRemoteDhtkey = remoteDhtkey | 719 | , hpCookieRemoteDhtkey = remoteDhtkey |
@@ -661,7 +752,7 @@ cryptoNetHandler sessions addr (NetCrypto (CryptoPacket nonce16 encrypted)) = do | |||
661 | Just session@(NCrypto { ncIncomingTypeArray, ncState, ncPacketQueue, ncHooks, | 752 | Just session@(NCrypto { ncIncomingTypeArray, ncState, ncPacketQueue, ncHooks, |
662 | ncSessionSecret, ncTheirSessionPublic, ncTheirBaseNonce, | 753 | ncSessionSecret, ncTheirSessionPublic, ncTheirBaseNonce, |
663 | ncPingMachine}) -> do | 754 | ncPingMachine}) -> do |
664 | theirBaseNonce <- atomically $ readTVar ncTheirBaseNonce | 755 | HaveHandshake theirBaseNonce <- atomically $ readTVar ncTheirBaseNonce |
665 | -- Try to decrypt message | 756 | -- Try to decrypt message |
666 | let diff :: Word16 | 757 | let diff :: Word16 |
667 | diff = nonce16 - (last2Bytes theirBaseNonce) -- truncating to Word16 | 758 | diff = nonce16 - (last2Bytes theirBaseNonce) -- truncating to Word16 |
@@ -699,11 +790,11 @@ cryptoNetHandler sessions addr (NetCrypto (CryptoPacket nonce16 encrypted)) = do | |||
699 | -- update ncTheirBaseNonce if necessary | 790 | -- update ncTheirBaseNonce if necessary |
700 | when (diff > 2 * dATA_NUM_THRESHOLD)$ | 791 | when (diff > 2 * dATA_NUM_THRESHOLD)$ |
701 | atomically $ do | 792 | atomically $ do |
702 | y <- readTVar ncTheirBaseNonce | 793 | HaveHandshake y <- readTVar ncTheirBaseNonce |
703 | let x = addtoNonce24 y (fromIntegral dATA_NUM_THRESHOLD) | 794 | let x = addtoNonce24 y (fromIntegral dATA_NUM_THRESHOLD) |
704 | trace ("nonce y(" ++ show y ++ ") + " ++ show (fromIntegral dATA_NUM_THRESHOLD) | 795 | trace ("nonce y(" ++ show y ++ ") + " ++ show (fromIntegral dATA_NUM_THRESHOLD) |
705 | ++ " = " ++ show x) (return ()) | 796 | ++ " = " ++ show x) (return ()) |
706 | writeTVar ncTheirBaseNonce y | 797 | writeTVar ncTheirBaseNonce (HaveHandshake y) |
707 | -- then set session confirmed, | 798 | -- then set session confirmed, |
708 | atomically $ writeTVar ncState Confirmed {-Established-} | 799 | atomically $ writeTVar ncState Confirmed {-Established-} |
709 | -- bump ping machine | 800 | -- bump ping machine |
@@ -807,7 +898,7 @@ allMsgTypes fDefault = A.listArray (minBound,maxBound) (0:knownMsgs) | |||
807 | 898 | ||
808 | sendCrypto :: TransportCrypto -> NetCryptoSession -> (STM ()) -> CryptoMessage -> IO (Either String ()) | 899 | sendCrypto :: TransportCrypto -> NetCryptoSession -> (STM ()) -> CryptoMessage -> IO (Either String ()) |
809 | sendCrypto crypto session updateLocal cm = do | 900 | sendCrypto crypto session updateLocal cm = do |
810 | let outq = ncOutgoingQueue session | 901 | let HaveHandshake outq = ncOutgoingQueue session |
811 | -- XXX: potential race? if shared secret comes out of sync with cache? | 902 | -- XXX: potential race? if shared secret comes out of sync with cache? |
812 | dput XNetCrypto "sendCrypto: enter " | 903 | dput XNetCrypto "sendCrypto: enter " |
813 | getOutGoingParam <- PQ.readyOutGoing outq | 904 | getOutGoingParam <- PQ.readyOutGoing outq |