add a UUID to pair requests

Pair requests the the same UUID are part of the same pairing session,
which allows us to detect attempts to brute force the shared secret,
as that will result in pair requests with the same UUID that are
not verified with the right secret.
This commit is contained in:
Joey Hess 2012-09-11 03:16:00 -04:00
parent b3f4c6eb68
commit 0208d6aa82
3 changed files with 26 additions and 7 deletions

View file

@ -7,6 +7,7 @@
module Assistant.Pairing where
import Common.Annex
import Utility.Verifiable
import Assistant.Ssh
@ -49,6 +50,7 @@ data PairData = PairData
, remoteUserName :: UserName
, remoteDirectory :: FilePath
, remoteSshPubKey :: SshPubKey
, pairUUID :: UUID
}
deriving (Eq, Read, Show)

View file

@ -36,8 +36,8 @@ pairListenerThread st dstatus scanremotes urlrenderer = thread $ withSocketsDo $
go sock cache = getmsg sock [] >>= \msg -> case readish msg of
Nothing -> go sock cache
Just m -> do
pip <- pairingInProgress <$> getDaemonStatus dstatus
let verified = maybe False (verifiedPairMsg m) pip
(pip, verified) <- verificationCheck m
=<< (pairingInProgress <$> getDaemonStatus dstatus)
case pairMsgStage m of
PairReq -> do
pairReqReceived verified dstatus urlrenderer m
@ -49,6 +49,23 @@ pairListenerThread st dstatus scanremotes urlrenderer = thread $ withSocketsDo $
pairDoneReceived verified pip st dstatus scanremotes m
go sock cache
{- As well as verifying the message using the shared secret,
- check its UUID against the UUID we have stored. If
- they're the same, someone is sending bogus messages,
- which could be an attempt to brute force the shared
- secret. -}
verificationCheck m (Just pip) = do
let verified = verifiedPairMsg m pip
let sameuuid = pairUUID (inProgressPairData pip) == pairUUID (pairMsgData $ m)
if (not verified && sameuuid)
then do
runThreadState st $
warning "detected possible pairing brute force attempt; disabled pairing"
stopSending dstatus pip
return (Nothing, False)
else return (Just pip, verified && sameuuid)
verificationCheck _ Nothing = return (Nothing, False)
{- PairReqs invalidate the cache of recently finished pairings.
- This is so that, if a new pairing is started with the
- same secret used before, a bogus PairDone is not sent. -}
@ -125,12 +142,10 @@ pairAckReceived _ _ _ dstatus _ msg cache = do
{- If we get a verified PairDone, the host has accepted our PairAck, and
- has paired with us. Stop sending PairAcks, and finish pairing with them.
-
- If we get an unverified PairDone that matches the PairReq
- TODO: Should third-party hosts remove their pair request alert when they
- see a PairDone? How to tell if a PairDone matches with the PairReq
- that brought up the alert? Cannot verify it without the secret..
- Also, the user could have already clicked on the alert and be entering
- the secret. Would be better to start a fresh pair request in this
- see a PairDone?
- Complication: The user could have already clicked on the alert and be
- entering the secret. Would be better to start a fresh pair request in this
- situation.
-}
pairDoneReceived :: Bool -> Maybe PairingInProgress -> ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> PairMsg -> IO ()

View file

@ -24,6 +24,7 @@ import Assistant.Alert
import Assistant.DaemonStatus
import Utility.Verifiable
import Utility.Network
import Annex.UUID
#endif
import Yesod
@ -91,6 +92,7 @@ startPairing stage oncancel displaysecret secret = do
<*> liftIO getUserName
<*> (fromJust . relDir <$> lift getYesod)
<*> pure (sshPubKey keypair)
<*> liftIO genUUID
liftIO $ do
let sender = multicastPairMsg Nothing secret stage pairdata
let pip = PairingInProgress secret Nothing keypair pairdata