{-# LANGUAGE OverloadedStrings #-} -- | -- Module : Network.TLS.Record.Engage13 -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : unknown -- -- Engage a record into the Record layer. -- The record is compressed, added some integrity field, then encrypted. -- module Network.TLS.Record.Engage13 ( engageRecord ) where import Control.Monad.State import Crypto.Cipher.Types (AuthTag(..)) import Network.TLS.Record.State import Network.TLS.Record.Types13 import Network.TLS.Cipher import Network.TLS.Wire import Network.TLS.Struct (valOfType) import Network.TLS.Struct13 import Network.TLS.Imports import Network.TLS.Util import qualified Data.ByteString as B import qualified Data.ByteArray as B (convert, xor) engageRecord :: Record13 -> RecordM Record13 engageRecord record@(Record13 ContentType_ChangeCipherSpec _) = return record engageRecord record@(Record13 ct bytes) = do st <- get case stCipher st of Nothing -> return record _ -> do ebytes <- encryptContent $ innerPlaintext ct bytes return $ Record13 ContentType_AppData ebytes innerPlaintext :: ContentType -> ByteString -> ByteString innerPlaintext ct bytes = runPut $ do putBytes bytes putWord8 $ valOfType ct -- non zero! -- fixme: zeros padding encryptContent :: ByteString -> RecordM ByteString encryptContent content = do st <- get let cst = stCryptState st case cstKey cst of BulkStateBlock _ -> error "encryptContent" BulkStateStream _ -> error "encryptContent" BulkStateUninitialized -> return content BulkStateAEAD encryptF -> do encodedSeq <- encodeWord64 <$> getMacSequence let iv = cstIV cst ivlen = B.length iv sqnc = B.replicate (ivlen - 8) 0 `B.append` encodedSeq nonce = B.xor iv sqnc bulk = cipherBulk $ fromJust "cipher" $ stCipher st authTagLen = bulkAuthTagLen bulk plainLen = B.length content econtentLen = plainLen + authTagLen additional = "\23\3\3" `B.append` encodeWord16 (fromIntegral econtentLen) (e, AuthTag authtag) = encryptF nonce content additional econtent = e `B.append` B.convert authtag modify incrRecordState return econtent