You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
3.0 KiB
75 lines
3.0 KiB
|
14 years ago
|
{-# LANGUAGE DeriveDataTypeable #-}
|
||
|
14 years ago
|
{-# LANGUAGE OverloadedStrings #-}
|
||
|
15 years ago
|
|
||
|
14 years ago
|
module Network.XMPP.TLS where
|
||
|
15 years ago
|
|
||
|
14 years ago
|
import qualified Control.Exception.Lifted as Ex
|
||
|
14 years ago
|
import Control.Monad
|
||
|
14 years ago
|
import Control.Monad.Error
|
||
|
|
import Control.Monad.State.Strict
|
||
|
15 years ago
|
|
||
|
14 years ago
|
import Data.Conduit.TLS as TLS
|
||
|
14 years ago
|
import Data.Typeable
|
||
|
14 years ago
|
import Data.XML.Types
|
||
|
15 years ago
|
|
||
|
14 years ago
|
import Network.XMPP.Monad
|
||
|
14 years ago
|
import Network.XMPP.Pickle(ppElement)
|
||
|
14 years ago
|
import Network.XMPP.Stream
|
||
|
|
import Network.XMPP.Types
|
||
|
15 years ago
|
|
||
|
14 years ago
|
starttlsE :: Element
|
||
|
14 years ago
|
starttlsE = Element "{urn:ietf:params:xml:ns:xmpp-tls}starttls" [] []
|
||
|
14 years ago
|
|
||
|
14 years ago
|
exampleParams :: TLS.TLSParams
|
||
|
14 years ago
|
exampleParams = TLS.defaultParams
|
||
|
14 years ago
|
{ pConnectVersion = TLS.TLS10
|
||
|
|
, pAllowedVersions = [TLS.SSL3, TLS.TLS10, TLS.TLS11]
|
||
|
|
, pCiphers = [TLS.cipher_AES128_SHA1]
|
||
|
|
, pCompressions = [TLS.nullCompression]
|
||
|
|
, pWantClientCert = False -- Used for servers
|
||
|
|
, pUseSecureRenegotiation = False -- No renegotiation
|
||
|
|
, pCertificates = [] -- TODO
|
||
|
|
, pLogging = TLS.defaultLogging -- TODO
|
||
|
|
, onCertificatesRecv = \_certificate ->
|
||
|
|
return TLS.CertificateUsageAccept
|
||
|
|
}
|
||
|
14 years ago
|
|
||
|
14 years ago
|
-- | Error conditions that may arise during TLS negotiation.
|
||
|
14 years ago
|
data XMPPTLSError = TLSError TLSError
|
||
|
|
| TLSNoServerSupport
|
||
|
|
| TLSNoConnection
|
||
|
|
| TLSStreamError StreamError
|
||
|
14 years ago
|
| XMPPTLSError -- General instance used for the Error instance
|
||
|
14 years ago
|
deriving (Show, Eq, Typeable)
|
||
|
|
|
||
|
|
instance Error XMPPTLSError where
|
||
|
14 years ago
|
noMsg = XMPPTLSError
|
||
|
14 years ago
|
|
||
|
14 years ago
|
-- Pushes "<starttls/>, waits for "<proceed/>", performs the TLS handshake, and
|
||
|
|
-- restarts the stream. May throw errors.
|
||
|
14 years ago
|
startTLS :: TLS.TLSParams -> XMPPConMonad (Either XMPPTLSError ())
|
||
|
14 years ago
|
startTLS params = Ex.handle (return . Left . TLSError) . runErrorT $ do
|
||
|
|
features <- lift $ gets sFeatures
|
||
|
|
handle' <- lift $ gets sConHandle
|
||
|
|
handle <- maybe (throwError TLSNoConnection) return handle'
|
||
|
|
when (stls features == Nothing) $ throwError TLSNoServerSupport
|
||
|
14 years ago
|
lift $ pushElement starttlsE
|
||
|
14 years ago
|
answer <- lift $ pullElement
|
||
|
|
case answer of
|
||
|
14 years ago
|
Element "{urn:ietf:params:xml:ns:xmpp-tls}proceed" [] [] -> return ()
|
||
|
14 years ago
|
Element "{urn:ietf:params:xml:ns:xmpp-tls}failure" _ _ ->
|
||
|
|
lift . Ex.throwIO $ StreamConnectionError
|
||
|
|
-- TODO: find something more suitable
|
||
|
|
e -> lift . Ex.throwIO . StreamXMLError $
|
||
|
|
"Unexpected element: " ++ ppElement e
|
||
|
|
(raw, _snk, psh, ctx) <- lift $ TLS.tlsinit params handle
|
||
|
|
lift $ modify ( \x -> x
|
||
|
|
{ sRawSrc = raw
|
||
|
|
-- , sConSrc = -- Note: this momentarily leaves us in an
|
||
|
|
-- inconsistent state
|
||
|
|
, sConPushBS = catchPush . psh
|
||
|
|
, sCloseConnection = TLS.bye ctx >> sCloseConnection x
|
||
|
|
})
|
||
|
|
either (lift . Ex.throwIO) return =<< lift xmppRestartStream
|
||
|
|
modify (\s -> s{sConnectionState = XmppConnectionSecured})
|
||
|
|
return ()
|