{-# LANGUAGE FlexibleContexts #-}
module Network.TLS.Receiving
( processPacket
, decodeRecordM
) where
import Network.TLS.Cipher
import Network.TLS.Context.Internal
import Network.TLS.ErrT
import Network.TLS.Handshake.State
import Network.TLS.Imports
import Network.TLS.Packet
import Network.TLS.Record
import Network.TLS.State
import Network.TLS.Struct
import Network.TLS.Util
import Network.TLS.Wire
import Control.Concurrent.MVar
import Control.Monad.State.Strict
processPacket :: Context -> Record Plaintext -> IO (Either TLSError Packet)
processPacket _ (Record ProtocolType_AppData _ fragment) = return $ Right $ AppData $ fragmentGetBytes fragment
processPacket _ (Record ProtocolType_Alert _ fragment) = return (Alert `fmapEither` decodeAlerts (fragmentGetBytes fragment))
processPacket ctx (Record ProtocolType_ChangeCipherSpec _ fragment) =
case decodeChangeCipherSpec $ fragmentGetBytes fragment of
Left err -> return $ Left err
Right _ -> do switchRxEncryption ctx
return $ Right ChangeCipherSpec
processPacket ctx (Record ProtocolType_Handshake ver fragment) = do
keyxchg <- getHState ctx >>= \hs -> return (hs >>= hstPendingCipher >>= Just . cipherKeyExchange)
usingState ctx $ do
let currentParams = CurrentParams
{ cParamsVersion = ver
, cParamsKeyXchgType = keyxchg
}
mCont <- gets stHandshakeRecordCont
modify (\st -> st { stHandshakeRecordCont = Nothing })
hss <- parseMany currentParams mCont (fragmentGetBytes fragment)
return $ Handshake hss
where parseMany currentParams mCont bs =
case fromMaybe decodeHandshakeRecord mCont bs of
GotError err -> throwError err
GotPartial cont -> modify (\st -> st { stHandshakeRecordCont = Just cont }) >> return []
GotSuccess (ty,content) ->
either throwError (return . (:[])) $ decodeHandshake currentParams ty content
GotSuccessRemaining (ty,content) left ->
case decodeHandshake currentParams ty content of
Left err -> throwError err
Right hh -> (hh:) <$> parseMany currentParams Nothing left
processPacket _ (Record ProtocolType_DeprecatedHandshake _ fragment) =
case decodeDeprecatedHandshake $ fragmentGetBytes fragment of
Left err -> return $ Left err
Right hs -> return $ Right $ Handshake [hs]
switchRxEncryption :: Context -> IO ()
switchRxEncryption ctx =
usingHState ctx (gets hstPendingRxState) >>= \rx ->
liftIO $ modifyMVar_ (ctxRxState ctx) (\_ -> return $ fromJust "rx-state" rx)
decodeRecordM :: Header -> ByteString -> RecordM (Record Plaintext)
decodeRecordM header content = disengageRecord erecord
where
erecord = rawToRecord header (fragmentCiphertext content)