1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
-- | TLS record layer in Rx direction
module Network.TLS.Record.Recv (
recvRecord12,
recvRecord13,
) where
import qualified Data.ByteString as B
import Network.TLS.Context.Internal
import Network.TLS.Hooks
import Network.TLS.Imports
import Network.TLS.Packet
import Network.TLS.Record
import Network.TLS.Struct
import Network.TLS.Types
----------------------------------------------------------------
getMyPlainLimit :: Context -> IO Int
getMyPlainLimit ctx = do
msiz <- getMyRecordLimit ctx
return $ case msiz of
Nothing -> defaultRecordSizeLimit
Just siz -> siz
getRecord
:: Context
-> Header
-> ByteString
-> IO (Either TLSError (Record Plaintext))
getRecord ctx header content = do
withLog ctx $ \logging -> loggingIORecv logging header content
lim <- getMyPlainLimit ctx
runRxRecordState ctx $ do
let erecord = rawToRecord header $ fragmentCiphertext content
decryptRecord erecord lim
----------------------------------------------------------------
exceedsTLSCiphertext :: Int -> Word16 -> Bool
exceedsTLSCiphertext overhead actual =
-- In TLS 1.3, overhead is included one more byte for content type.
fromIntegral actual > defaultRecordSizeLimit + overhead
-- | recvRecord receive a full TLS record (header + data), from the other side.
--
-- The record is disengaged from the record layer
recvRecord12
:: Context
-- ^ TLS context
-> IO (Either TLSError (Record Plaintext))
recvRecord12 ctx =
readExactBytes ctx 5 >>= either (return . Left) (recvLengthE . decodeHeader)
where
recvLengthE = either (return . Left) recvLength
recvLength header@(Header _ _ readlen) = do
-- RFC 5246 Section 7.2.2
-- A TLSCiphertext record was received that had a length more
-- than 2^14+2048 bytes, or a record decrypted to a
-- TLSCompressed record with more than 2^14+1024 bytes. This
-- message is always fatal and should never be observed in
-- communication between proper implementations (except when
-- messages were corrupted in the network).
if exceedsTLSCiphertext 2048 readlen
then return $ Left maximumSizeExceeded
else
readExactBytes ctx (fromIntegral readlen)
>>= either (return . Left) (getRecord ctx header)
recvRecord13 :: Context -> IO (Either TLSError (Record Plaintext))
recvRecord13 ctx = readExactBytes ctx 5 >>= either (return . Left) (recvLengthE . decodeHeader)
where
recvLengthE = either (return . Left) recvLength
recvLength header@(Header _ _ readlen) = do
-- RFC 8446 Section 5.2:
-- An AEAD algorithm used in TLS 1.3 MUST NOT produce an
-- expansion greater than 255 octets. An endpoint that
-- receives a record from its peer with TLSCiphertext.length
-- larger than 2^14 + 256 octets MUST terminate the connection
-- with a "record_overflow" alert. This limit is derived from
-- the maximum TLSInnerPlaintext length of 2^14 octets + 1
-- octet for ContentType + the maximum AEAD expansion of 255
-- octets.
if exceedsTLSCiphertext 256 readlen
then return $ Left maximumSizeExceeded
else
readExactBytes ctx (fromIntegral readlen)
>>= either (return . Left) (getRecord ctx header)
maximumSizeExceeded :: TLSError
maximumSizeExceeded = Error_Protocol "record exceeding maximum size" RecordOverflow
----------------------------------------------------------------
readExactBytes :: Context -> Int -> IO (Either TLSError ByteString)
readExactBytes ctx sz = do
hdrbs <- contextRecv ctx sz
if B.length hdrbs == sz
then return $ Right hdrbs
else do
setEOF ctx
return . Left $
if B.null hdrbs
then Error_EOF
else
Error_Packet
( "partial packet: expecting "
++ show sz
++ " bytes, got: "
++ show (B.length hdrbs)
)
|