1-- |
2-- Module      : Network.TLS.Record.Writing
3-- License     : BSD-style
4-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
5-- Stability   : experimental
6-- Portability : unknown
7--
8-- TLS record layer in Tx direction
9--
10module Network.TLS.Record.Writing
11    ( encodeRecord
12    , encodeRecord13
13    , sendBytes
14    ) where
15
16import Network.TLS.Cap
17import Network.TLS.Cipher
18import Network.TLS.Context.Internal
19import Network.TLS.Hooks
20import Network.TLS.Imports
21import Network.TLS.Packet
22import Network.TLS.Parameters
23import Network.TLS.Record
24import Network.TLS.State
25import Network.TLS.Struct
26
27import Control.Concurrent.MVar
28import Control.Monad.State.Strict
29import qualified Data.ByteString as B
30
31encodeRecord :: Context -> Record Plaintext -> IO (Either TLSError ByteString)
32encodeRecord ctx = prepareRecord ctx . encodeRecordM
33
34-- before TLS 1.1, the block cipher IV is made of the residual of the previous block,
35-- so we use cstIV as is, however in other case we generate an explicit IV
36prepareRecord :: Context -> RecordM a -> IO (Either TLSError a)
37prepareRecord ctx f = do
38    ver     <- usingState_ ctx (getVersionWithDefault $ maximum $ supportedVersions $ ctxSupported ctx)
39    txState <- readMVar $ ctxTxState ctx
40    let sz = case stCipher txState of
41                  Nothing     -> 0
42                  Just cipher -> if hasRecordIV $ bulkF $ cipherBulk cipher
43                                    then bulkIVSize $ cipherBulk cipher
44                                    else 0 -- to not generate IV
45    if hasExplicitBlockIV ver && sz > 0
46        then do newIV <- getStateRNG ctx sz
47                runTxState ctx (modify (setRecordIV newIV) >> f)
48        else runTxState ctx f
49
50encodeRecordM :: Record Plaintext -> RecordM ByteString
51encodeRecordM record = do
52    erecord <- engageRecord record
53    let (hdr, content) = recordToRaw erecord
54    return $ B.concat [ encodeHeader hdr, content ]
55
56----------------------------------------------------------------
57
58encodeRecord13 :: Context -> Record Plaintext -> IO (Either TLSError ByteString)
59encodeRecord13 ctx = prepareRecord13 ctx . encodeRecordM
60
61prepareRecord13 :: Context -> RecordM a -> IO (Either TLSError a)
62prepareRecord13 = runTxState
63
64----------------------------------------------------------------
65
66sendBytes :: Context -> ByteString -> IO ()
67sendBytes ctx dataToSend = do
68    withLog ctx $ \logging -> loggingIOSent logging dataToSend
69    contextSend ctx dataToSend
70