hs-tls/core/Network/TLS/Receiving.hs

168 lines
7.1 KiB
Haskell
Raw Normal View History

2010-09-09 21:47:19 +00:00
-- |
-- Module : Network.TLS.Receiving
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
-- the Receiving module contains calls related to unmarshalling packets according
-- to the TLS state
--
2013-07-09 06:15:54 +00:00
module Network.TLS.Receiving
( processHandshake
, processPacket
, processServerHello
, verifyRSA
) where
2010-09-09 21:47:19 +00:00
2010-10-02 21:02:37 +00:00
import Control.Applicative ((<$>))
2010-09-09 21:47:19 +00:00
import Control.Monad.State
import Control.Monad.Error
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
2010-09-09 21:47:19 +00:00
import Network.TLS.Types (Role(..))
import Network.TLS.Util
2010-09-09 21:47:19 +00:00
import Network.TLS.Struct
import Network.TLS.Record
2010-09-09 21:47:19 +00:00
import Network.TLS.Packet
import Network.TLS.State
2013-07-20 06:18:16 +00:00
import Network.TLS.Handshake.State
2010-09-09 21:47:19 +00:00
import Network.TLS.Cipher
import Network.TLS.Crypto
import Network.TLS.Extension
2013-05-19 07:05:46 +00:00
import Data.X509
2010-09-09 21:47:19 +00:00
returnEither :: Either TLSError a -> TLSSt a
2010-09-09 21:47:19 +00:00
returnEither (Left err) = throwError err
returnEither (Right a) = return a
processPacket :: Record Plaintext -> TLSSt Packet
2010-09-09 21:47:19 +00:00
processPacket (Record ProtocolType_AppData _ fragment) = return $ AppData $ fragmentGetBytes fragment
2010-10-02 08:09:46 +00:00
processPacket (Record ProtocolType_Alert _ fragment) = return . Alert =<< returnEither (decodeAlerts $ fragmentGetBytes fragment)
2010-10-02 08:09:46 +00:00
processPacket (Record ProtocolType_ChangeCipherSpec _ fragment) = do
2013-07-09 06:19:16 +00:00
returnEither $ decodeChangeCipherSpec $ fragmentGetBytes fragment
runRecordStateSt switchRxEncryption
2013-07-09 06:19:16 +00:00
return ChangeCipherSpec
2010-09-09 21:47:19 +00:00
processPacket (Record ProtocolType_Handshake ver fragment) = do
keyxchg <- runRecordStateSt getCipherKeyExchangeType
2013-07-09 06:19:16 +00:00
npn <- getExtensionNPN
let currentparams = CurrentParams
{ cParamsVersion = ver
, cParamsKeyXchgType = maybe CipherKeyExchange_RSA id $ 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
return $ Handshake hss
processPacket (Record ProtocolType_DeprecatedHandshake _ fragment) =
2013-07-09 06:19:16 +00:00
case decodeDeprecatedHandshake $ fragmentGetBytes fragment of
Left err -> throwError err
Right hs -> return $ Handshake [hs]
processHandshake :: Handshake -> TLSSt ()
processHandshake hs = do
role <- isClientContext
2013-07-09 06:19:16 +00:00
case hs of
ClientHello cver ran _ _ _ ex _ -> when (role == ServerRole) $ do
2013-07-09 06:19:16 +00:00
mapM_ processClientExtension ex
startHandshakeClient cver ran
Certificates certs -> processCertificates role certs
ClientKeyXchg content -> when (role == ServerRole) $ do
2013-07-09 06:19:16 +00:00
processClientKeyXchg content
HsNextProtocolNegotiation selected_protocol ->
when (role == ServerRole) $ setNegotiatedProtocol selected_protocol
2013-07-09 06:19:16 +00:00
Finished fdata -> processClientFinished fdata
_ -> return ()
let encoded = encodeHandshake hs
when (certVerifyHandshakeMaterial hs) $ withHandshakeM $ addHandshakeMessage encoded
when (finishHandshakeTypeMaterial $ typeOfHandshake hs) $ withHandshakeM $ updateHandshakeDigest encoded
2013-07-09 06:19:16 +00:00
where -- secure renegotiation
processClientExtension (0xff01, content) = do
v <- getVerifiedData True
let bs = extensionEncode (SecureRenegotiation v Nothing)
unless (bs `bytesEq` content) $ throwError $ Error_Protocol ("client verified data not matching: " ++ show v ++ ":" ++ show content, True, HandshakeFailure)
setSecureRenegotiation True
-- unknown extensions
processClientExtension _ = return ()
2011-12-20 07:47:46 +00:00
decryptRSA :: ByteString -> TLSSt (Either KxError ByteString)
decryptRSA econtent = do
ver <- getRecordState stVersion
2013-07-09 06:19:16 +00:00
rsapriv <- fromJust "rsa private key" . hstRSAPrivateKey . fromJust "handshake" . stHandshake <$> get
let cipher = if ver < TLS10 then econtent else B.drop 2 econtent
runRecordStateSt $ do
st <- get
let (mmsg,rng') = withTLSRNG (stRandomGen st) (\g -> kxDecrypt g rsapriv cipher)
put (st { stRandomGen = rng' })
return mmsg
2011-12-20 07:47:46 +00:00
2012-12-30 15:31:13 +00:00
verifyRSA :: HashDescr -> ByteString -> ByteString -> TLSSt Bool
verifyRSA hsh econtent sign = do
2013-07-09 06:19:16 +00:00
rsapriv <- fromJust "rsa client public key" . hstRSAClientPublicKey . fromJust "handshake" . stHandshake <$> get
return $ kxVerify rsapriv hsh econtent sign
processServerHello :: Handshake -> TLSSt ()
processServerHello (ServerHello sver ran _ _ _ ex) = do
2013-07-09 06:19:16 +00:00
-- FIXME notify the user to take action if the extension requested is missing
-- secreneg <- getSecureRenegotiation
-- when (secreneg && (isNothing $ lookup 0xff01 ex)) $ ...
mapM_ processServerExtension ex
setServerRandom ran
setVersion sver
where processServerExtension (0xff01, content) = do
cv <- getVerifiedData True
sv <- getVerifiedData False
let bs = extensionEncode (SecureRenegotiation cv $ Just sv)
unless (bs `bytesEq` content) $ throwError $ Error_Protocol ("server secure renegotiation data not matching", True, HandshakeFailure)
return ()
processServerExtension _ = return ()
processServerHello _ = error "processServerHello called on wrong type"
2010-09-09 21:47:19 +00:00
2011-04-24 10:34:11 +00:00
-- process the client key exchange message. the protocol expects the initial
-- client version received in ClientHello, not the negotiated version.
2011-04-24 10:34:11 +00:00
-- in case the version mismatch, generate a random master secret
processClientKeyXchg :: ByteString -> TLSSt ()
processClientKeyXchg encryptedPremaster = do
ver <- getVersion
role <- isClientContext
2013-07-09 06:19:16 +00:00
expectedVer <- hstClientVersion . fromJust "handshake" . stHandshake <$> get
2013-07-13 07:03:25 +00:00
random <- genRandom 48
2013-07-09 06:19:16 +00:00
ePremaster <- decryptRSA encryptedPremaster
case ePremaster of
Left _ -> setMasterSecretFromPre ver role random
2013-07-09 06:19:16 +00:00
Right premaster -> case decodePreMasterSecret premaster of
Left _ -> setMasterSecretFromPre ver role random
2013-07-09 06:19:16 +00:00
Right (ver, _)
| ver /= expectedVer -> setMasterSecretFromPre ver role random
| otherwise -> setMasterSecretFromPre ver role premaster
2010-09-09 21:47:19 +00:00
processClientFinished :: FinishedData -> TLSSt ()
2010-09-09 21:47:19 +00:00
processClientFinished fdata = do
cc <- isClientContext
expected <- getHandshakeDigest (cc == ServerRole)
2013-07-09 06:19:16 +00:00
when (expected /= fdata) $ do
throwError $ Error_Protocol("bad record mac", True, BadRecordMac)
updateVerifiedData ServerRole fdata
2013-07-09 06:19:16 +00:00
return ()
2010-09-09 21:47:19 +00:00
processCertificates :: Role -> CertificateChain -> TLSSt ()
processCertificates ServerRole (CertificateChain []) = return ()
processCertificates ClientRole (CertificateChain []) =
2013-05-19 07:05:46 +00:00
throwError $ Error_Protocol ("server certificate missing", True, HandshakeFailure)
processCertificates role (CertificateChain (c:_))
| role == ClientRole = withHandshakeM $ setPublicKey pubkey
| otherwise = withHandshakeM $ setClientPublicKey pubkey
where pubkey = certPubKey $ getCertificate c