diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Network/Tox/Crypto/Handlers.hs | 144 |
1 files changed, 91 insertions, 53 deletions
diff --git a/src/Network/Tox/Crypto/Handlers.hs b/src/Network/Tox/Crypto/Handlers.hs index bde286fe..0027e414 100644 --- a/src/Network/Tox/Crypto/Handlers.hs +++ b/src/Network/Tox/Crypto/Handlers.hs | |||
@@ -225,7 +225,7 @@ data NetCryptoSession = NCrypto | |||
225 | , ncHandShake :: TVar (UponHandshake (Handshake Encrypted)) | 225 | , ncHandShake :: TVar (UponHandshake (Handshake Encrypted)) |
226 | , ncCookie :: TVar (UponCookie Cookie) -- ^ Cookie issued by remote peer | 226 | , ncCookie :: TVar (UponCookie Cookie) -- ^ Cookie issued by remote peer |
227 | , ncTheirDHTKey :: UponDHTKey PublicKey | 227 | , ncTheirDHTKey :: UponDHTKey PublicKey |
228 | , ncTheirSessionPublic :: UponHandshake PublicKey | 228 | , ncTheirSessionPublic :: TVar (UponHandshake PublicKey) |
229 | , ncSessionSecret :: SecretKey | 229 | , ncSessionSecret :: SecretKey |
230 | , ncSockAddr :: UponDHTKey SockAddr | 230 | , ncSockAddr :: UponDHTKey SockAddr |
231 | -- The remaining fields correspond to implementation specific state -- | 231 | -- The remaining fields correspond to implementation specific state -- |
@@ -550,22 +550,14 @@ freshCryptoSession sessions | |||
550 | mbpktoq | 550 | mbpktoq |
551 | <- case mbtheirSessionKey of | 551 | <- case mbtheirSessionKey of |
552 | Nothing -> return NeedHandshake | 552 | Nothing -> return NeedHandshake |
553 | Just theirSessionKey -> do | 553 | Just theirSessionKey -> createNetCryptoOutQueue sessions newsession theirSessionKey pktq ncMyPacketNonce0 ncOutgoingIdMap0 |
554 | let toWireIO = do | ||
555 | f <- lookupNonceFunction crypto newsession theirSessionKey | ||
556 | atomically $ do | ||
557 | n24 <- readTVar ncMyPacketNonce0 | ||
558 | let n24plus1 = incrementNonce24 n24 | ||
559 | trace ("ncMyPacketNonce+1=" ++ show n24plus1) $ writeTVar ncMyPacketNonce0 n24plus1 | ||
560 | return (return (f n24, n24, ncOutgoingIdMap0)) | ||
561 | pktoq <- atomically $ PQ.newOutGoing pktq ncToWire toWireIO 0 (outboundQueueCapacity sessions) 0 | ||
562 | return (HaveHandshake pktoq) | ||
563 | lastNQ <- atomically (CB.new 10 0 :: STM (CyclicBuffer (Bool,(ViewSnapshot,InOrOut CryptoMessage)))) | 554 | lastNQ <- atomically (CB.new 10 0 :: STM (CyclicBuffer (Bool,(ViewSnapshot,InOrOut CryptoMessage)))) |
564 | listeners <- atomically $ newTVar IntMap.empty | 555 | listeners <- atomically $ newTVar IntMap.empty |
565 | msgNum <- atomically $ newTVar 0 | 556 | msgNum <- atomically $ newTVar 0 |
566 | dropNum <- atomically $ newTVar 0 | 557 | dropNum <- atomically $ newTVar 0 |
567 | theirbasenonce <- atomically $ readTVar ncTheirBaseNonce0 | 558 | theirbasenonce <- atomically $ readTVar ncTheirBaseNonce0 |
568 | dput XNetCrypto $ "freshCryptoSession: Session ncTheirBaseNonce=" ++ show theirbasenonce | 559 | dput XNetCrypto $ "freshCryptoSession: Session ncTheirBaseNonce=" ++ show theirbasenonce |
560 | ncTheirSessionPublic0 <- atomically $ newTVar (frmMaybe mbtheirSessionKey) | ||
569 | let netCryptoSession0 = | 561 | let netCryptoSession0 = |
570 | NCrypto { ncState = ncState0 | 562 | NCrypto { ncState = ncState0 |
571 | , ncMyPublicKey = toPublic key | 563 | , ncMyPublicKey = toPublic key |
@@ -576,7 +568,7 @@ freshCryptoSession sessions | |||
576 | , ncHandShake = ncHandShake0 | 568 | , ncHandShake = ncHandShake0 |
577 | , ncCookie = cookie0 | 569 | , ncCookie = cookie0 |
578 | , ncTheirDHTKey = HaveDHTKey remoteDhtPublicKey | 570 | , ncTheirDHTKey = HaveDHTKey remoteDhtPublicKey |
579 | , ncTheirSessionPublic = frmMaybe mbtheirSessionKey | 571 | , ncTheirSessionPublic = ncTheirSessionPublic0 |
580 | , ncSessionSecret = newsession | 572 | , ncSessionSecret = newsession |
581 | , ncSockAddr = HaveDHTKey addr | 573 | , ncSockAddr = HaveDHTKey addr |
582 | , ncHooks = ncHooks0 | 574 | , ncHooks = ncHooks0 |
@@ -594,7 +586,40 @@ freshCryptoSession sessions | |||
594 | , ncLastNMsgs = lastNQ | 586 | , ncLastNMsgs = lastNQ |
595 | , ncListeners = listeners | 587 | , ncListeners = listeners |
596 | } | 588 | } |
589 | case mbpktoq of | ||
590 | NeedHandshake -> return () | ||
591 | HaveHandshake pktoq -> runUponHandshake netCryptoSession0 addr pktoq | ||
592 | |||
593 | type NetCryptoOutQueue = PQ.PacketOutQueue (State,Nonce24,RangeMap TArray Word8 TVar) | ||
594 | CryptoMessage | ||
595 | (CryptoPacket Encrypted) | ||
596 | CryptoData | ||
597 | |||
598 | createNetCryptoOutQueue :: NetCryptoSessions -> SecretKey -> PublicKey -> PacketQueue CryptoData | ||
599 | -> TVar Nonce24 -> RangeMap TArray Word8 TVar -> IO (UponHandshake NetCryptoOutQueue) | ||
600 | createNetCryptoOutQueue sessions newsession theirSessionKey pktq ncMyPacketNonce0 ncOutgoingIdMap0 = do | ||
601 | let crypto = transportCrypto sessions | ||
602 | let toWireIO = do | ||
603 | f <- lookupNonceFunction crypto newsession theirSessionKey | ||
604 | atomically $ do | ||
605 | n24 <- readTVar ncMyPacketNonce0 | ||
606 | let n24plus1 = incrementNonce24 n24 | ||
607 | trace ("ncMyPacketNonce+1=" ++ show n24plus1) $ writeTVar ncMyPacketNonce0 n24plus1 | ||
608 | return (return (f n24, n24, ncOutgoingIdMap0)) | ||
609 | pktoq <- atomically $ PQ.newOutGoing pktq ncToWire toWireIO 0 (outboundQueueCapacity sessions) 0 | ||
610 | return (HaveHandshake pktoq) | ||
611 | |||
612 | |||
613 | runUponHandshake :: NetCryptoSession -> SockAddr -> NetCryptoOutQueue -> IO () | ||
614 | runUponHandshake netCryptoSession0 addr pktoq = do | ||
615 | let sessions = ncAllSessions netCryptoSession0 | ||
616 | pktq = ncPacketQueue netCryptoSession0 | ||
617 | remotePublicKey = ncTheirPublicKey netCryptoSession0 | ||
618 | crypto = transportCrypto sessions | ||
619 | allsessions = netCryptoSessions sessions | ||
620 | allsessionsByKey = netCryptoSessionsByKey sessions | ||
597 | -- launch dequeue thread | 621 | -- launch dequeue thread |
622 | -- (In terms of data dependency, this thread could be launched prior to handshake) | ||
598 | threadid <- forkIO $ do | 623 | threadid <- forkIO $ do |
599 | tid <- myThreadId | 624 | tid <- myThreadId |
600 | labelThread tid ("NetCryptoDequeue." ++ show (key2id remotePublicKey)) | 625 | labelThread tid ("NetCryptoDequeue." ++ show (key2id remotePublicKey)) |
@@ -602,44 +627,41 @@ freshCryptoSession sessions | |||
602 | cd <- atomically $ PQ.dequeue pktq | 627 | cd <- atomically $ PQ.dequeue pktq |
603 | _ <- runCryptoHook (netCryptoSession0 {ncDequeueThread=Just tid}) (bufferData cd) | 628 | _ <- runCryptoHook (netCryptoSession0 {ncDequeueThread=Just tid}) (bufferData cd) |
604 | loop | 629 | loop |
605 | case mbpktoq of | 630 | -- launch dequeueOutgoing thread |
606 | NeedHandshake -> return () | 631 | threadidOutgoing <- forkIO $ do |
607 | HaveHandshake pktoq -> do | 632 | tid <- myThreadId |
608 | -- launch dequeueOutgoing thread | 633 | labelThread tid ("NetCryptoDequeueOutgoing." ++ show (key2id remotePublicKey)) |
609 | threadidOutgoing <- forkIO $ do | 634 | fix $ \loop -> do |
610 | tid <- myThreadId | 635 | (_,pkt) <- atomically $ PQ.dequeueOutgoing pktoq |
611 | labelThread tid ("NetCryptoDequeueOutgoing." ++ show (key2id remotePublicKey)) | 636 | dput XNetCrypto "NetCryptoDequeueOutgoing thread... Sending encrypted Packet" |
612 | fix $ \loop -> do | 637 | sendMessage (sessionTransport sessions) addr (NetCrypto pkt) |
613 | (_,pkt) <- atomically $ PQ.dequeueOutgoing pktoq | 638 | loop |
614 | dput XNetCrypto "NetCryptoDequeueOutgoing thread... Sending encrypted Packet" | 639 | -- launch ping thread |
615 | sendMessage (sessionTransport sessions) addr (NetCrypto pkt) | 640 | fuzz <- randomRIO (0,2000) |
616 | loop | 641 | pingMachine <- forkPingMachine ("NetCrypto." ++ show (key2id remotePublicKey)) (15000 + fuzz) 2000 |
617 | -- launch ping thread | 642 | -- update session with thread ids |
618 | fuzz <- randomRIO (0,2000) | 643 | let netCryptoSession = netCryptoSession0 {ncDequeueThread=Just threadid, ncPingMachine=Just pingMachine} |
619 | pingMachine <- forkPingMachine ("NetCrypto." ++ show (key2id remotePublicKey)) (15000 + fuzz) 2000 | 644 | -- add this session to the lookup maps |
620 | -- update session with thread ids | 645 | atomically $ do |
621 | let netCryptoSession = netCryptoSession0 {ncDequeueThread=Just threadid, ncPingMachine=Just pingMachine} | 646 | modifyTVar allsessions (Map.insert addr netCryptoSession) |
622 | -- add this session to the lookup maps | 647 | byKeyResult <- readTVar allsessionsByKey >>= return . Map.lookup remotePublicKey |
623 | atomically $ do | 648 | case byKeyResult of |
624 | modifyTVar allsessions (Map.insert addr netCryptoSession) | 649 | Nothing -> modifyTVar allsessionsByKey (Map.insert remotePublicKey [netCryptoSession]) |
625 | byKeyResult <- readTVar allsessionsByKey >>= return . Map.lookup remotePublicKey | 650 | Just xs -> modifyTVar allsessionsByKey (Map.insert remotePublicKey (netCryptoSession:xs)) |
626 | case byKeyResult of | 651 | -- run announceNewSessionHooks |
627 | Nothing -> modifyTVar allsessionsByKey (Map.insert remotePublicKey [netCryptoSession]) | 652 | hooks <- atomically $ readTVar (announceNewSessionHooks sessions) |
628 | Just xs -> modifyTVar allsessionsByKey (Map.insert remotePublicKey (netCryptoSession:xs)) | 653 | flip fix (hooks,netCryptoSession) $ \loop (hooks,session) -> |
629 | -- run announceNewSessionHooks | 654 | case hooks of |
630 | hooks <- atomically $ readTVar (announceNewSessionHooks sessions) | 655 | [] -> return () |
631 | flip fix (hooks,netCryptoSession) $ \loop (hooks,session) -> | 656 | (h:hs) -> do |
632 | case hooks of | 657 | r <- h Nothing session |
633 | [] -> return () | 658 | case r of |
634 | (h:hs) -> do | 659 | Just f -> loop (hs, f session) |
635 | r <- h Nothing session | 660 | Nothing -> return () |
636 | case r of | ||
637 | Just f -> loop (hs, f session) | ||
638 | Nothing -> return () | ||
639 | 661 | ||
640 | -- | Called when we get a handshake, but there's already a session entry. | 662 | -- | Called when we get a handshake, but there's already a session entry. |
641 | updateCryptoSession :: NetCryptoSessions -> SockAddr -> HandshakeParams -> NetCryptoSession -> IO () | 663 | updateCryptoSession :: NetCryptoSessions -> SockAddr -> HandshakeParams -> NetCryptoSession -> Handshake Encrypted -> IO () |
642 | updateCryptoSession sessions addr hp session = do | 664 | updateCryptoSession sessions addr hp session handshake = do |
643 | ncState0 <- atomically $ readTVar (ncState session) | 665 | ncState0 <- atomically $ readTVar (ncState session) |
644 | ncTheirBaseNonce0 <- atomically $ readTVar (ncTheirBaseNonce session) | 666 | ncTheirBaseNonce0 <- atomically $ readTVar (ncTheirBaseNonce session) |
645 | if (ncState0 >= {-Accepted-}InProgress AwaitingSessionPacket) | 667 | if (ncState0 >= {-Accepted-}InProgress AwaitingSessionPacket) |
@@ -656,10 +678,25 @@ updateCryptoSession sessions addr hp session = do | |||
656 | dput XNetCrypto (" ncTheirDHTKey=" ++ show (ncTheirDHTKey session) | 678 | dput XNetCrypto (" ncTheirDHTKey=" ++ show (ncTheirDHTKey session) |
657 | ++ bool "{/=}" "{==}" (ncTheirDHTKey session == HaveDHTKey (hpCookieRemoteDhtkey hp)) | 679 | ++ bool "{/=}" "{==}" (ncTheirDHTKey session == HaveDHTKey (hpCookieRemoteDhtkey hp)) |
658 | ++ "hpCookieRemoteDhtkey=" ++ show (hpCookieRemoteDhtkey hp)) | 680 | ++ "hpCookieRemoteDhtkey=" ++ show (hpCookieRemoteDhtkey hp)) |
659 | when ( -- Just ncTheirBaseNonce0 /= hpTheirBaseNonce hp -- XXX: Do we really want to compare base nonce here? | 681 | if ( -- Just ncTheirBaseNonce0 /= hpTheirBaseNonce hp -- XXX: Do we really want to compare base nonce here? |
660 | -- || | 682 | -- || |
661 | ncTheirDHTKey session /= HaveDHTKey (hpCookieRemoteDhtkey hp) | 683 | ncTheirDHTKey session /= HaveDHTKey (hpCookieRemoteDhtkey hp) |
662 | ) $ freshCryptoSession sessions addr hp | 684 | ) then freshCryptoSession sessions addr hp |
685 | else do | ||
686 | atomically $ do | ||
687 | writeTVar (ncTheirBaseNonce session) (frmMaybe (hpTheirBaseNonce hp)) | ||
688 | writeTVar (ncTheirSessionPublic session) (frmMaybe (hpTheirSessionKeyPublic hp)) | ||
689 | writeTVar (ncHandShake session) (HaveHandshake handshake) | ||
690 | case ncOutgoingQueue session of | ||
691 | NeedHandshake -> do | ||
692 | case hpTheirSessionKeyPublic hp of | ||
693 | Just sessionpubkey -> do | ||
694 | pktoq <- createNetCryptoOutQueue sessions (ncSessionSecret session) sessionpubkey | ||
695 | (ncPacketQueue session) (ncMyPacketNonce session) (ncOutgoingIdMap session) | ||
696 | case pktoq of | ||
697 | NeedHandshake -> dput XNetCrypto "Unexpectedly missing ncOutgoingQueue" | ||
698 | HaveHandshake pktoq -> runUponHandshake session addr pktoq | ||
699 | HaveHandshake pktoq -> runUponHandshake session addr pktoq | ||
663 | else do | 700 | else do |
664 | dput XNetCrypto "updateCryptoSession else clause" | 701 | dput XNetCrypto "updateCryptoSession else clause" |
665 | dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0 | 702 | dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0 |
@@ -674,7 +711,7 @@ cryptoNetHandler sessions addr (NetHandshake hs) = handshakeH sessions addr | |||
674 | cryptoNetHandler sessions addr (NetCrypto pkt) = sessionPacketH sessions addr pkt | 711 | cryptoNetHandler sessions addr (NetCrypto pkt) = sessionPacketH sessions addr pkt |
675 | 712 | ||
676 | handshakeH :: NetCryptoSessions -> SockAddr -> Handshake Encrypted -> IO (Maybe a) | 713 | handshakeH :: NetCryptoSessions -> SockAddr -> Handshake Encrypted -> IO (Maybe a) |
677 | handshakeH sessions addr (Handshake (Cookie n24 ecookie) nonce24 encrypted) = do | 714 | handshakeH sessions addr hshake@(Handshake (Cookie n24 ecookie) nonce24 encrypted) = do |
678 | dput XNetCrypto ("RECIEVED HANDSHAKE from " ++ show addr) | 715 | dput XNetCrypto ("RECIEVED HANDSHAKE from " ++ show addr) |
679 | -- Handle Handshake Message | 716 | -- Handle Handshake Message |
680 | let crypto = transportCrypto sessions | 717 | let crypto = transportCrypto sessions |
@@ -746,7 +783,7 @@ handshakeH sessions addr (Handshake (Cookie n24 ecookie) nonce24 encrypted) = do | |||
746 | freshCryptoSession sessions addr hp -- create new session | 783 | freshCryptoSession sessions addr hp -- create new session |
747 | Just session -> do | 784 | Just session -> do |
748 | dput XNetCrypto "sockaddr ALREADY in session map, so updateCryptoSession" | 785 | dput XNetCrypto "sockaddr ALREADY in session map, so updateCryptoSession" |
749 | updateCryptoSession sessions addr hp session -- update existing session | 786 | updateCryptoSession sessions addr hp session hshake -- update existing session |
750 | return Nothing | 787 | return Nothing |
751 | 788 | ||
752 | sessionPacketH :: NetCryptoSessions -> SockAddr -> CryptoPacket Encrypted -> IO (Maybe (x -> x)) | 789 | sessionPacketH :: NetCryptoSessions -> SockAddr -> CryptoPacket Encrypted -> IO (Maybe (x -> x)) |
@@ -771,8 +808,9 @@ sessionPacketH sessions addr (CryptoPacket nonce16 encrypted) = do | |||
771 | let diff :: Word16 | 808 | let diff :: Word16 |
772 | diff = nonce16 - (last2Bytes theirBaseNonce) -- truncating to Word16 | 809 | diff = nonce16 - (last2Bytes theirBaseNonce) -- truncating to Word16 |
773 | tempNonce = addtoNonce24 theirBaseNonce (fromIntegral diff) -- expanding to Word | 810 | tempNonce = addtoNonce24 theirBaseNonce (fromIntegral diff) -- expanding to Word |
811 | mbpublickey <- atomically (readTVar ncTheirSessionPublic) | ||
774 | lr <- fmap join $ sequence $ do -- Either Monad -- | 812 | lr <- fmap join $ sequence $ do -- Either Monad -- |
775 | pubkey <- maybeToEither ncTheirSessionPublic | 813 | pubkey <- maybeToEither mbpublickey |
776 | Right $ do -- IO Monad | 814 | Right $ do -- IO Monad |
777 | dput XNetCrypto $ "cryptoNetHandler: pubkey = " ++ show (key2id $ pubkey) | 815 | dput XNetCrypto $ "cryptoNetHandler: pubkey = " ++ show (key2id $ pubkey) |
778 | dput XNetCrypto $ "cryptoNetHandler: theirBaseNonce = " ++ show theirBaseNonce | 816 | dput XNetCrypto $ "cryptoNetHandler: theirBaseNonce = " ++ show theirBaseNonce |