Mutual authentication: server side
authorunc0rr
Sun, 26 Jan 2014 02:17:04 +0400
changeset 10076 b235e520ea21
parent 10075 dbaf90a0fbe0
child 10077 ca67740f19b2
Mutual authentication: server side
QTfrontend/net/newnetclient.cpp
gameServer/Actions.hs
gameServer/Consts.hs
gameServer/CoreTypes.hs
gameServer/HWProtoNEState.hs
gameServer/NetRoutines.hs
gameServer/hedgewars-server.cabal
--- a/QTfrontend/net/newnetclient.cpp	Sun Jan 26 00:09:50 2014 +0400
+++ b/QTfrontend/net/newnetclient.cpp	Sun Jan 26 02:17:04 2014 +0400
@@ -239,7 +239,7 @@
 void HWNewNet::SendPasswordHash(const QString & hash)
 {
     // don't send it immediately, only store and check if server asked us for a password
-    m_passwordHash = hash;
+    m_passwordHash = hash.toAscii();
 
     maybeSendPassword();
 }
@@ -311,7 +311,7 @@
             return;
         }
 
-        if(lst[2] != m_serverHash)
+        if(lst[1] != m_serverHash)
         {
             Error("Server authentication error");
             Disconnect();
@@ -1145,15 +1145,13 @@
     if(m_passwordHash.isEmpty() || m_serverSalt.isEmpty())
         return;
 
-    QString hash;
-
-    hash = QCryptographicHash::hash(
+    QString hash = QCryptographicHash::hash(
                 m_clientSalt.toAscii()
                 .append(m_serverSalt.toAscii())
                 .append(m_passwordHash)
                 .append(cProtoVer->toAscii())
                 .append("!hedgewars")
-                , QCryptographicHash::Sha1);
+                , QCryptographicHash::Sha1).toHex();
 
     m_serverHash = QCryptographicHash::hash(
                 m_serverSalt.toAscii()
@@ -1161,7 +1159,7 @@
                 .append(m_passwordHash)
                 .append(cProtoVer->toAscii())
                 .append("!hedgewars")
-                , QCryptographicHash::Sha1);
+                , QCryptographicHash::Sha1).toHex();
 
     RawSendNet(QString("PASSWORD%1%2%1%3").arg(delimeter).arg(hash).arg(m_clientSalt));
 }
--- a/gameServer/Actions.hs	Sun Jan 26 00:09:50 2014 +0400
+++ b/gameServer/Actions.hs	Sun Jan 26 02:17:04 2014 +0400
@@ -466,9 +466,9 @@
                 else
                 [ByeClient $ loc "Authentication failed"]
     playerLogin p a contr = do
-        chan <- client's sendChan
+        cl <- client's id
         mapM_ processAction [
-            AnswerClients [chan] ["ASKPASSWORD"]
+            AnswerClients [sendChan cl] $ ("ASKPASSWORD") : if clientProto cl < 48 then [] else [serverSalt cl]
             , ModifyClient (\c -> c{webPassword = p, isAdministrator = a, isContributor = contr})
             ]
 
--- a/gameServer/Consts.hs	Sun Jan 26 00:09:50 2014 +0400
+++ b/gameServer/Consts.hs	Sun Jan 26 02:17:04 2014 +0400
@@ -4,4 +4,4 @@
 import qualified Data.ByteString.Char8 as B
 
 serverVersion :: B.ByteString
-serverVersion = "2"
+serverVersion = "3"
--- a/gameServer/CoreTypes.hs	Sun Jan 26 00:09:50 2014 +0400
+++ b/gameServer/CoreTypes.hs	Sun Jan 26 02:17:04 2014 +0400
@@ -98,6 +98,7 @@
         connectTime :: UTCTime,
         nick :: B.ByteString,
         webPassword :: B.ByteString,
+        serverSalt :: B.ByteString,
         logonPassed :: Bool,
         isVisible :: Bool,
         clientProto :: !Word16,
--- a/gameServer/HWProtoNEState.hs	Sun Jan 26 00:09:50 2014 +0400
+++ b/gameServer/HWProtoNEState.hs	Sun Jan 26 02:17:04 2014 +0400
@@ -2,7 +2,9 @@
 module HWProtoNEState where
 
 import Control.Monad.Reader
+import qualified Data.ByteString.Lazy as BL
 import qualified Data.ByteString.Char8 as B
+import Data.Digest.Pure.SHA
 --------------------------------------
 import CoreTypes
 import Actions
@@ -42,12 +44,29 @@
     (ci, irnc) <- ask
     let cl = irnc `client` ci
 
-    if passwd == webPassword cl then
+    if clientProto cl < 48 && passwd == webPassword cl then
         return $ JoinLobby : [AnswerClients [sendChan cl] ["ADMIN_ACCESS"] | isAdministrator cl]
         else
         return [ByeClient "Authentication failed"]
 
 
+handleCmd_NotEntered ["PASSWORD", passwd, clientSalt] = do
+    (ci, irnc) <- ask
+    let cl = irnc `client` ci
+
+    let clientHash = h [clientSalt, serverSalt cl, webPassword cl, showB $ clientProto cl, "!hedgewars"]
+    let serverHash = h [serverSalt cl, clientSalt, webPassword cl, showB $ clientProto cl, "!hedgewars"]
+
+    if passwd == clientHash then
+        return $
+            AnswerClients [sendChan cl] ["SERVER_AUTH", serverHash] 
+            : JoinLobby
+            : [AnswerClients [sendChan cl] ["ADMIN_ACCESS"] | isAdministrator cl]
+        else
+        return [ByeClient "Authentication failed"]
+    where
+        h = B.pack . showDigest . sha1 . BL.fromChunks
+
 #if defined(OFFICIAL_SERVER)
 handleCmd_NotEntered ["CHECKER", protoNum, newNick, password] = do
     (ci, irnc) <- ask
--- a/gameServer/NetRoutines.hs	Sun Jan 26 00:09:50 2014 +0400
+++ b/gameServer/NetRoutines.hs	Sun Jan 26 02:17:04 2014 +0400
@@ -6,13 +6,20 @@
 import Data.Time
 import Control.Monad
 import Data.Unique
+import qualified Codec.Binary.Base64 as Base64
+import qualified Data.ByteString as BW
+import qualified Data.ByteString.Char8 as B
+import qualified Control.Exception as E
+import System.Entropy
 -----------------------------
 import CoreTypes
 import Utils
-import RoomsAndClients
+
 
 acceptLoop :: Socket -> Chan CoreMessage -> IO ()
-acceptLoop servSock chan = forever $
+acceptLoop servSock chan = E.bracket openHandle closeHandle f
+    where
+    f ch = forever $
         do
         (sock, sockAddr) <- Network.Socket.accept servSock
 
@@ -23,6 +30,7 @@
         sendChan' <- newChan
 
         uid <- newUnique
+        salt <- liftM (B.pack . Base64.encode . BW.unpack) $ hGetEntropy ch 16
 
         let newClient =
                 (ClientInfo
@@ -33,6 +41,7 @@
                     currentTime
                     ""
                     ""
+                    salt
                     False
                     False
                     0
--- a/gameServer/hedgewars-server.cabal	Sun Jan 26 00:09:50 2014 +0400
+++ b/gameServer/hedgewars-server.cabal	Sun Jan 26 02:17:04 2014 +0400
@@ -28,6 +28,8 @@
     hslogger,
     process,
     deepseq,
-    utf8-string
+    utf8-string,
+    SHA,
+    entropy
 
   ghc-options: -O2