diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+## Version 1.2.3 (22 Mar 2014)
+
+- Fixed handshake records not being able to span multiples records.
diff --git a/Network/TLS/Backend.hs b/Network/TLS/Backend.hs
--- a/Network/TLS/Backend.hs
+++ b/Network/TLS/Backend.hs
@@ -5,11 +5,11 @@
 -- Stability   : experimental
 -- Portability : unknown
 --
--- Backend represent a unified way to do IO on differents
--- types without burdening our calling API with multiples
--- way to initialize a new context.
+-- A Backend represents a unified way to do IO on different
+-- types without burdening our calling API with multiple
+-- ways to initialize a new context.
 --
--- Typically any backend much implement:
+-- Typically, a backend provides:
 -- * a way to read data
 -- * a way to write data
 -- * a way to close the stream
diff --git a/Network/TLS/Core.hs b/Network/TLS/Core.hs
--- a/Network/TLS/Core.hs
+++ b/Network/TLS/Core.hs
@@ -81,21 +81,8 @@
 
         process (Handshake [ch@(ClientHello {})]) =
             withRWLock ctx ((ctxDoHandshakeWith ctx) ctx ch) >> recvData ctx
-            {-
-            case roleParams $ ctxParams ctx of
-                Server sparams -> withRWLock ctx (handshakeServerWith sparams ctx ch) >> recvData ctx
-                Client {}      -> let reason = "unexpected client hello in client context" in
-                                  terminate (Error_Misc reason) AlertLevel_Fatal UnexpectedMessage reason
-                                  -}
         process (Handshake [hr@HelloRequest]) =
             withRWLock ctx ((ctxDoHandshakeWith ctx) ctx hr) >> recvData ctx
-            {-
-            -- on client context, receiving a hello request == renegotiation
-            case roleParams $ ctxParams ctx of
-                Server {}      -> let reason = "unexpected hello request in server context" in
-                                  terminate (Error_Misc reason) AlertLevel_Fatal UnexpectedMessage reason
-                Client cparams -> withRWLock ctx (handshakeClient cparams ctx) >> recvData ctx
-                -}
 
         process (Alert [(AlertLevel_Warning, CloseNotify)]) = tryBye >> setEOF ctx >> return B.empty
         process (Alert [(AlertLevel_Fatal, desc)]) = do
diff --git a/Network/TLS/Internal.hs b/Network/TLS/Internal.hs
--- a/Network/TLS/Internal.hs
+++ b/Network/TLS/Internal.hs
@@ -11,6 +11,7 @@
     , module Network.TLS.Packet
     , module Network.TLS.Receiving
     , module Network.TLS.Sending
+    , module Network.TLS.Wire
     , sendPacket
     , recvPacket
     ) where
@@ -19,4 +20,5 @@
 import Network.TLS.Packet
 import Network.TLS.Receiving
 import Network.TLS.Sending
+import Network.TLS.Wire
 import Network.TLS.Core (sendPacket, recvPacket)
diff --git a/Network/TLS/Packet.hs b/Network/TLS/Packet.hs
--- a/Network/TLS/Packet.hs
+++ b/Network/TLS/Packet.hs
@@ -26,7 +26,7 @@
     , encodeAlerts
 
     -- * marshall functions for handshake messages
-    , decodeHandshakes
+    , decodeHandshakeRecord
     , decodeHandshake
     , decodeDeprecatedHandshake
     , encodeHandshake
@@ -157,23 +157,14 @@
   where encodeAlert (al, ad) = putWord8 (valOfType al) >> putWord8 (valOfType ad)
 
 {- decode and encode HANDSHAKE -}
-decodeHandshakeHeader :: Get (HandshakeType, Bytes)
-decodeHandshakeHeader = do
+decodeHandshakeRecord :: ByteString -> GetResult (HandshakeType, Bytes)
+decodeHandshakeRecord = runGet "handshake-record" $ do
     ty      <- getHandshakeType
     content <- getOpaque24
     return (ty, content)
 
-decodeHandshakes :: ByteString -> Either TLSError [(HandshakeType, Bytes)]
-decodeHandshakes b = runGetErr "handshakes" getAll b
-  where getAll = do
-            x <- decodeHandshakeHeader
-            empty <- isEmpty
-            if empty
-                then return [x]
-                else liftM ((:) x) getAll
-
 decodeHandshake :: CurrentParams -> HandshakeType -> ByteString -> Either TLSError Handshake
-decodeHandshake cp ty = runGetErr "handshake" $ case ty of
+decodeHandshake cp ty = runGetErr ("handshake[" ++ show ty ++ "]") $ case ty of
     HandshakeType_HelloRequest    -> decodeHelloRequest
     HandshakeType_ClientHello     -> decodeClientHello
     HandshakeType_ServerHello     -> decodeServerHello
diff --git a/Network/TLS/Receiving.hs b/Network/TLS/Receiving.hs
--- a/Network/TLS/Receiving.hs
+++ b/Network/TLS/Receiving.hs
@@ -20,23 +20,22 @@
 import Network.TLS.Struct
 import Network.TLS.Record
 import Network.TLS.Packet
+import Network.TLS.Wire
 import Network.TLS.State
 import Network.TLS.Handshake.State
 import Network.TLS.Cipher
 import Network.TLS.Util
 
-returnEither :: Either TLSError a -> TLSSt a
-returnEither (Left err) = throwError err
-returnEither (Right a)  = return a
+import Data.Byteable
 
 processPacket :: Context -> Record Plaintext -> IO (Either TLSError Packet)
 
-processPacket _ (Record ProtocolType_AppData _ fragment) = return $ Right $ AppData $ fragmentGetBytes fragment
+processPacket _ (Record ProtocolType_AppData _ fragment) = return $ Right $ AppData $ toBytes fragment
 
-processPacket _ (Record ProtocolType_Alert _ fragment) = return (Alert `fmapEither` (decodeAlerts $ fragmentGetBytes fragment))
+processPacket _ (Record ProtocolType_Alert _ fragment) = return (Alert `fmapEither` (decodeAlerts $ toBytes fragment))
 
 processPacket ctx (Record ProtocolType_ChangeCipherSpec _ fragment) =
-    case decodeChangeCipherSpec $ fragmentGetBytes fragment of
+    case decodeChangeCipherSpec $ toBytes fragment of
         Left err -> return $ Left err
         Right _  -> do switchRxEncryption ctx
                        return $ Right ChangeCipherSpec
@@ -45,20 +44,29 @@
     keyxchg <- getHState ctx >>= \hs -> return $ (hs >>= hstPendingCipher >>= Just . cipherKeyExchange)
     usingState ctx $ do
         npn     <- getExtensionNPN
-        let currentparams = CurrentParams
+        let currentParams = CurrentParams
                             { cParamsVersion     = ver
                             , cParamsKeyXchgType = keyxchg
                             , cParamsSupportNPN  = npn
                             }
-        handshakes <- returnEither (decodeHandshakes $ fragmentGetBytes fragment)
-        hss <- forM handshakes $ \(ty, content) -> do
-            case decodeHandshake currentparams ty content of
-                    Left err -> throwError err
-                    Right hs -> return hs
+        -- get back the optional continuation, and parse as many handshake record as possible.
+        mCont <- gets stHandshakeRecordCont
+        modify (\st -> st { stHandshakeRecordCont = Nothing })
+        hss   <- parseMany currentParams mCont (toBytes fragment)
         return $ Handshake hss
+  where parseMany currentParams mCont bs =
+            case maybe decodeHandshakeRecord id 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:) `fmap` parseMany currentParams Nothing left
 
 processPacket _ (Record ProtocolType_DeprecatedHandshake _ fragment) =
-    case decodeDeprecatedHandshake $ fragmentGetBytes fragment of
+    case decodeDeprecatedHandshake $ toBytes fragment of
         Left err -> return $ Left err
         Right hs -> return $ Right $ Handshake [hs]
 
diff --git a/Network/TLS/Record.hs b/Network/TLS/Record.hs
--- a/Network/TLS/Record.hs
+++ b/Network/TLS/Record.hs
@@ -15,7 +15,6 @@
     ( Record(..)
     -- * Fragment manipulation types
     , Fragment
-    , fragmentGetBytes
     , fragmentPlaintext
     , fragmentCiphertext
     , recordToRaw
diff --git a/Network/TLS/Record/Types.hs b/Network/TLS/Record/Types.hs
--- a/Network/TLS/Record/Types.hs
+++ b/Network/TLS/Record/Types.hs
@@ -22,7 +22,6 @@
     , Fragment
     , fragmentPlaintext
     , fragmentCiphertext
-    , fragmentGetBytes
     , Plaintext
     , Compressed
     , Ciphertext
@@ -41,6 +40,7 @@
 import Network.TLS.Struct
 import Network.TLS.Record.State
 import qualified Data.ByteString as B
+import Data.Byteable
 import Control.Applicative ((<$>))
 
 -- | Represent a TLS record.
@@ -58,8 +58,8 @@
 fragmentCiphertext :: Bytes -> Fragment Ciphertext
 fragmentCiphertext bytes = Fragment bytes
 
-fragmentGetBytes :: Fragment a -> Bytes
-fragmentGetBytes (Fragment bytes) = bytes
+instance Byteable (Fragment a) where
+    toBytes (Fragment b) = b
 
 onRecordFragment :: Record a -> (Fragment a -> RecordM (Fragment b)) -> RecordM (Record b)
 onRecordFragment (Record pt ver frag) f = Record pt ver <$> f frag
diff --git a/Network/TLS/State.hs b/Network/TLS/State.hs
--- a/Network/TLS/State.hs
+++ b/Network/TLS/State.hs
@@ -51,6 +51,7 @@
 import Network.TLS.Struct
 import Network.TLS.RNG
 import Network.TLS.Types (Role(..))
+import Network.TLS.Wire (GetContinuation)
 import qualified Data.ByteString as B
 import Control.Monad.State
 import Control.Monad.Error
@@ -64,13 +65,14 @@
     , stClientVerifiedData  :: Bytes -- RFC 5746
     , stServerVerifiedData  :: Bytes -- RFC 5746
     , stExtensionNPN        :: Bool  -- NPN draft extension
+    , stHandshakeRecordCont :: Maybe (GetContinuation (HandshakeType, Bytes))
     , stNegotiatedProtocol  :: Maybe B.ByteString -- NPN protocol
     , stServerNextProtocolSuggest :: Maybe [B.ByteString]
     , stClientCertificateChain :: Maybe CertificateChain
     , stRandomGen           :: StateRNG
     , stVersion             :: Maybe Version
     , stClientContext       :: Role
-    } deriving (Show)
+    }
 
 newtype TLSSt a = TLSSt { runTLSSt :: ErrorT TLSError (State TLSState) a }
     deriving (Monad, MonadError TLSError, Functor, Applicative)
@@ -93,6 +95,7 @@
     , stClientVerifiedData  = B.empty
     , stServerVerifiedData  = B.empty
     , stExtensionNPN        = False
+    , stHandshakeRecordCont = Nothing
     , stNegotiatedProtocol  = Nothing
     , stServerNextProtocolSuggest = Nothing
     , stClientCertificateChain = Nothing
diff --git a/Network/TLS/Wire.hs b/Network/TLS/Wire.hs
--- a/Network/TLS/Wire.hs
+++ b/Network/TLS/Wire.hs
@@ -10,9 +10,12 @@
 --
 module Network.TLS.Wire
     ( Get
+    , GetResult(..)
+    , GetContinuation
     , runGet
     , runGetErr
     , runGetMaybe
+    , tryGet
     , remaining
     , getWord8
     , getWords8
@@ -54,14 +57,33 @@
 import Network.TLS.Struct
 import Network.TLS.Util.Serialization
 
-runGet :: String -> Get a -> Bytes -> Either String a
-runGet lbl f = G.runGet (label lbl f)
+type GetContinuation a = Bytes -> GetResult a
+data GetResult a =
+      GotError TLSError
+    | GotPartial (GetContinuation a)
+    | GotSuccess a
+    | GotSuccessRemaining a Bytes
 
+runGet :: String -> Get a -> Bytes -> GetResult a
+runGet lbl f = toGetResult <$> G.runGetPartial (label lbl f)
+  where toGetResult (G.Fail err _)    = GotError (Error_Packet_Parsing err)
+        toGetResult (G.Partial cont)  = GotPartial (toGetResult <$> cont)
+        toGetResult (G.Done r bsLeft)
+            | B.null bsLeft = GotSuccess r
+            | otherwise     = GotSuccessRemaining r bsLeft
+
 runGetErr :: String -> Get a -> Bytes -> Either TLSError a
-runGetErr lbl f = either (Left . Error_Packet_Parsing) Right . runGet lbl f
+runGetErr lbl getter b = toSimple $ runGet lbl getter b
+  where toSimple (GotError err) = Left err
+        toSimple (GotPartial _) = Left (Error_Packet_Parsing (lbl ++ ": parsing error: partial packet"))
+        toSimple (GotSuccessRemaining _ _) = Left (Error_Packet_Parsing (lbl ++ ": parsing error: remaining bytes"))
+        toSimple (GotSuccess r) = Right r
 
 runGetMaybe :: Get a -> Bytes -> Maybe a
-runGetMaybe f = either (const Nothing) Just . runGet "" f
+runGetMaybe f = either (const Nothing) Just . G.runGet f
+
+tryGet :: Get a -> Bytes -> Maybe a
+tryGet f = either (const Nothing) Just . G.runGet f
 
 getWords8 :: Get [Word8]
 getWords8 = getWord8 >>= \lenb -> replicateM (fromIntegral lenb) getWord8
diff --git a/Tests/Marshalling.hs b/Tests/Marshalling.hs
--- a/Tests/Marshalling.hs
+++ b/Tests/Marshalling.hs
@@ -103,5 +103,9 @@
 
 prop_handshake_marshalling_id :: Handshake -> Bool
 prop_handshake_marshalling_id x = (decodeHs $ encodeHandshake x) == Right x
-  where decodeHs b = either (Left . id) (uncurry (decodeHandshake cp) . head) $ decodeHandshakes b
+  where decodeHs b = case decodeHandshakeRecord b of
+                        GotPartial _ -> error "got partial"
+                        GotError e   -> error ("got error: " ++ show e)
+                        GotSuccessRemaining _ _ -> error "got remaining byte left"
+                        GotSuccess (ty, content) -> decodeHandshake cp ty content
         cp = CurrentParams { cParamsVersion = TLS10, cParamsKeyXchgType = Just CipherKeyExchange_RSA, cParamsSupportNPN = True }
diff --git a/tls.cabal b/tls.cabal
--- a/tls.cabal
+++ b/tls.cabal
@@ -1,5 +1,5 @@
 Name:                tls
-Version:             1.2.2
+Version:             1.2.3
 Description:
    Native Haskell TLS and SSL protocol implementation for server and client.
    .
@@ -8,11 +8,11 @@
    type system, high level constructions and common Haskell features.
    .
    Currently implement the SSL3.0, TLS1.0, TLS1.1 and TLS1.2 protocol,
-   with only RSA supported for Key Exchange.
+   and support RSA and Ephemeral Diffie Hellman key exchanges,
+   and many extensions.
    .
-   Only core protocol available here, have a look at the
-   <http://hackage.haskell.org/package/tls-extra/> package for default
-   ciphers, compressions and certificates functions.
+   Some debug tools linked with tls, are available through the
+   <http://hackage.haskell.org/package/tls-debug/>.
 License:             BSD3
 License-file:        LICENSE
 Copyright:           Vincent Hanquez <vincent@snarc.org>
@@ -25,6 +25,7 @@
 Cabal-Version:       >=1.8
 Homepage:            http://github.com/vincenthz/hs-tls
 extra-source-files:  Tests/*.hs
+                     CHANGELOG.md
 
 Flag compat
   Description:       Accept SSLv2 compatible handshake
@@ -35,6 +36,7 @@
                    , mtl
                    , cereal >= 0.3
                    , bytestring
+                   , byteable
                    , network
                    , data-default-class
                    -- crypto related
