Switch handshake to exception instead of returning a bool.

Bool return value doesn't provide any information on why the handshake failed,
hence remove the Bool value, and return (), and in case of handshake failure,
raise a HandshakeFailed exception with the TLSError associated with it.
This commit is contained in:
Vincent Hanquez 2012-01-18 06:29:29 +00:00
parent 3b271b0c03
commit c846d9a360
2 changed files with 27 additions and 23 deletions

View file

@ -1,4 +1,5 @@
{-# OPTIONS_HADDOCK hide #-} {-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE DeriveDataTypeable #-}
-- | -- |
-- Module : Network.TLS.Core -- Module : Network.TLS.Core
-- License : BSD-style -- License : BSD-style
@ -21,6 +22,7 @@ module Network.TLS.Core
-- * Initialisation and Termination of context -- * Initialisation and Termination of context
, bye , bye
, handshake , handshake
, HandshakeFailed
-- * High level API -- * High level API
, sendData , sendData
@ -39,6 +41,7 @@ import Network.TLS.Receiving
import Network.TLS.Measurement import Network.TLS.Measurement
import Network.TLS.Wire (encodeWord16) import Network.TLS.Wire (encodeWord16)
import Data.Maybe import Data.Maybe
import Data.Data
import Data.List (intersect, find) import Data.List (intersect, find)
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
@ -51,10 +54,18 @@ import System.IO (Handle)
import System.IO.Error (mkIOError, eofErrorType) import System.IO.Error (mkIOError, eofErrorType)
import Prelude hiding (catch) import Prelude hiding (catch)
data HandshakeFailed = HandshakeFailed TLSError
deriving (Show,Eq,Typeable)
instance Exception HandshakeFailed
errorToAlert :: TLSError -> Packet errorToAlert :: TLSError -> Packet
errorToAlert (Error_Protocol (_, _, ad)) = Alert [(AlertLevel_Fatal, ad)] errorToAlert (Error_Protocol (_, _, ad)) = Alert [(AlertLevel_Fatal, ad)]
errorToAlert _ = Alert [(AlertLevel_Fatal, InternalError)] errorToAlert _ = Alert [(AlertLevel_Fatal, InternalError)]
handshakeFailed :: TLSError -> IO ()
handshakeFailed err = throwIO $ HandshakeFailed err
readExact :: MonadIO m => TLSCtx c -> Int -> m Bytes readExact :: MonadIO m => TLSCtx c -> Int -> m Bytes
readExact ctx sz = do readExact ctx sz = do
hdrbs <- liftIO $ connectionRecv ctx sz hdrbs <- liftIO $ connectionRecv ctx sz
@ -441,15 +452,15 @@ handshakeServer ctx = do
-- | Handshake for a new TLS connection -- | Handshake for a new TLS connection
-- This is to be called at the beginning of a connection, and during renegociation -- This is to be called at the beginning of a connection, and during renegociation
handshake :: MonadIO m => TLSCtx c -> m Bool handshake :: MonadIO m => TLSCtx c -> m ()
handshake ctx = do handshake ctx = do
cc <- usingState_ ctx (stClientContext <$> get) cc <- usingState_ ctx (stClientContext <$> get)
liftIO $ handleException $ if cc then handshakeClient ctx else handshakeServer ctx liftIO $ handleException $ if cc then handshakeClient ctx else handshakeServer ctx
where where
handleException f = catch (f >> return True) (\e -> handler e >> return False) handleException f = catch f $ \exception -> do
handler e = case fromException e of let tlserror = maybe (Error_Misc $ show exception) id $ fromException exception
Just err -> sendPacket ctx (errorToAlert err) sendPacket ctx (errorToAlert tlserror)
Nothing -> sendPacket ctx (errorToAlert $ Error_Misc $ show e) handshakeFailed tlserror
-- | sendData sends a bunch of data. -- | sendData sends a bunch of data.
-- It will automatically chunk data to acceptable packet size -- It will automatically chunk data to acceptable packet size

View file

@ -170,14 +170,12 @@ prop_handshake_initiate = do
return () return ()
where where
tlsServer ctx queue = do tlsServer ctx queue = do
hSuccess <- handshake ctx handshake ctx
unless hSuccess $ fail "handshake failed on server side"
d <- recvData ctx d <- recvData ctx
writeChan queue d writeChan queue d
return () return ()
tlsClient queue ctx = do tlsClient queue ctx = do
hSuccess <- handshake ctx handshake ctx
unless hSuccess $ fail "handshake failed on client side"
d <- readChan queue d <- readChan queue
sendData ctx d sendData ctx d
bye ctx bye ctx
@ -199,16 +197,13 @@ prop_handshake_renegociation = do
return () return ()
where where
tlsServer ctx queue = do tlsServer ctx queue = do
hSuccess <- handshake ctx handshake ctx
unless hSuccess $ fail "handshake failed on server side"
d <- recvData ctx d <- recvData ctx
writeChan queue d writeChan queue d
return () return ()
tlsClient queue ctx = do tlsClient queue ctx = do
hSuccess <- handshake ctx handshake ctx
unless hSuccess $ fail "handshake failed on client side" handshake ctx
hSuccess2 <- handshake ctx
unless hSuccess2 $ fail "renegociation handshake failed"
d <- readChan queue d <- readChan queue
sendData ctx d sendData ctx d
bye ctx bye ctx
@ -239,23 +234,21 @@ prop_handshake_session_resumption = do
{- the test involves writing data on one side of the data "pipe" and {- the test involves writing data on one side of the data "pipe" and
- then checking we received them on the other side of the data "pipe" -} - then checking we received them on the other side of the data "pipe" -}
d <- L.pack <$> pick (someWords8 256) d2 <- L.pack <$> pick (someWords8 256)
run $ writeChan startQueue d run $ writeChan startQueue d2
dres <- run $ readChan resultQueue dres2 <- run $ readChan resultQueue
d `assertEq` dres d2 `assertEq` dres2
return () return ()
where where
tlsServer ctx queue = do tlsServer ctx queue = do
hSuccess <- handshake ctx handshake ctx
unless hSuccess $ fail "resumption failed on server side"
d <- recvData ctx d <- recvData ctx
writeChan queue d writeChan queue d
return () return ()
tlsClient queue ctx = do tlsClient queue ctx = do
hSuccess <- handshake ctx handshake ctx
unless hSuccess $ fail "resumption failed on client side"
d <- readChan queue d <- readChan queue
sendData ctx d sendData ctx d
bye ctx bye ctx