@ -27,6 +27,7 @@ import qualified Data.Text.Encoding as Text
@@ -27,6 +27,7 @@ import qualified Data.Text.Encoding as Text
import Data.Word ( Word8 )
import Network.Xmpp.Sasl.Common
import Network.Xmpp.Sasl.StringPrep
import Network.Xmpp.Sasl.Types
-- | Bit-wise xor of byte strings
@ -57,12 +58,21 @@ scram :: (Crypto.Hash ctx hash)
@@ -57,12 +58,21 @@ scram :: (Crypto.Hash ctx hash)
-> Maybe Text . Text -- ^ authorization ID
-> Text . Text -- ^ password
-> SaslM ()
scram hashToken authcid authzid' password = do
scram hashToken authcid authzid password = case credentials of
Nothing -> throwError $ AuthStringPrepError
Just ( ac , az , pw ) -> scramhelper hashToken ac az pw
where
credentials = do
ac <- normalizeUsername authcid
az <- case authzid of
Nothing -> Just Nothing
Just az' -> Just <$> normalizeUsername az'
pw <- normalizePassword password
return ( ac , az , pw )
scramhelper hashToken authcid authzid' password = do
cnonce <- liftIO $ makeNonce
saslInit " SCRAM-SHA-1 " ( Just $ cFirstMessage cnonce )
liftIO $ putStrLn " pulling challenge "
sFirstMessage <- saslFromJust =<< pullChallenge
liftIO $ putStrLn " pulled challenge "
pairs <- toPairs sFirstMessage
( nonce , salt , ic ) <- fromPairs pairs cnonce
let ( cfm , v ) = cFinalMessageAndVerifier nonce salt ic sFirstMessage cnonce
@ -77,14 +87,14 @@ scram hashToken authcid authzid' password = do
@@ -77,14 +87,14 @@ scram hashToken authcid authzid' password = do
hash str = encode hashToken $ Crypto . hash' str
hmac key str = encode hashToken $ Crypto . hmac' ( Crypto . MacKey key ) str
authzid = ( \ z -> " a= " +++ normalize z ) <$> authzid'
authzid = ( \ z -> " a= " +++ Text . encodeUtf8 z ) <$> authzid'
gs2CbindFlag = " n " -- we don't support channel binding yet
gs2Header = merge $ [ gs2CbindFlag
, maybe " " id authzid
, " "
]
cbindData = " " -- we don't support channel binding yet
cFirstMessageBare cnonce = merge [ " n= " +++ normalize authcid
cFirstMessageBare cnonce = merge [ " n= " +++ Text . encodeUtf8 authcid
, " r= " +++ cnonce ]
cFirstMessage cnonce = gs2Header +++ cFirstMessageBare cnonce
@ -109,7 +119,7 @@ scram hashToken authcid authzid' password = do
@@ -109,7 +119,7 @@ scram hashToken authcid authzid' password = do
where
cFinalMessageWOProof = merge [ " c= " +++ B64 . encode gs2Header
, " r= " +++ nonce ]
saltedPassword = hi ( normalize password ) salt ic
saltedPassword = hi ( Text . encodeUtf8 password ) salt ic
clientKey = hmac saltedPassword " Client Key "
storedKey = hash clientKey
authMessage = merge [ cFirstMessageBare cnonce
@ -127,13 +137,12 @@ scram hashToken authcid authzid' password = do
@@ -127,13 +137,12 @@ scram hashToken authcid authzid' password = do
u1 = hmac str ( salt +++ ( BS . pack [ 0 , 0 , 0 , 1 ] ) )
us = iterate ( hmac str ) u1
normalize = Text . encodeUtf8 . id -- TODO: stringprep
base64 = B64 . encode
-- | 'scram' spezialised to the SHA-1 hash function, packaged as a SaslHandler
scramSha1 :: SaslM Text . Text -> SaslHandler
scramSha1 passwd = ( " SCRAM-SHA-1 "
, \ _hostname authcid authzid -> do
pw <- passwd
scram ( hashToken :: Crypto . SHA1 ) authcid authzid pw
scramSha1 :: Text . Text -- ^ username
-> Maybe Text . Text -- ^ authorization ID
-> Text . Text -- ^ password
-> SaslHandler
scramSha1 authcid authzid passwd =
( " SCRAM-SHA-1 "
, scram ( hashToken :: Crypto . SHA1 ) authcid authzid passwd
)