2012-12-05 07:57:13 +00:00
|
|
|
module Connection
|
2013-07-21 05:57:26 +00:00
|
|
|
( newPairContext
|
|
|
|
, arbitraryPairParams
|
|
|
|
, setPairParamsSessionManager
|
|
|
|
, setPairParamsSessionResuming
|
2013-07-21 06:37:58 +00:00
|
|
|
, establishDataPipe
|
2013-07-21 07:57:56 +00:00
|
|
|
, blockCipher
|
|
|
|
, streamCipher
|
2013-07-21 05:57:26 +00:00
|
|
|
) where
|
2011-11-14 22:12:09 +00:00
|
|
|
|
|
|
|
import Test.QuickCheck
|
2012-12-05 07:57:13 +00:00
|
|
|
import Certificate
|
|
|
|
import PubKey
|
|
|
|
import PipeChan
|
2011-11-14 22:12:09 +00:00
|
|
|
import Network.TLS
|
2013-05-19 07:05:46 +00:00
|
|
|
import Data.X509
|
2013-12-28 15:25:54 +00:00
|
|
|
import Control.Applicative
|
2013-07-21 06:37:58 +00:00
|
|
|
import Control.Concurrent.Chan
|
|
|
|
import Control.Concurrent
|
|
|
|
import qualified Control.Exception as E
|
2011-11-14 22:12:09 +00:00
|
|
|
|
|
|
|
import qualified Crypto.Random.AESCtr as RNG
|
|
|
|
import qualified Data.ByteString as B
|
|
|
|
|
2011-12-06 00:12:30 +00:00
|
|
|
debug = False
|
|
|
|
|
2011-12-11 20:43:32 +00:00
|
|
|
blockCipher :: Cipher
|
|
|
|
blockCipher = Cipher
|
2013-07-21 05:57:26 +00:00
|
|
|
{ cipherID = 0xff12
|
|
|
|
, cipherName = "rsa-id-const"
|
|
|
|
, cipherBulk = Bulk
|
|
|
|
{ bulkName = "id"
|
|
|
|
, bulkKeySize = 16
|
|
|
|
, bulkIVSize = 16
|
|
|
|
, bulkBlockSize = 16
|
|
|
|
, bulkF = BulkBlockF (\_ _ m -> m) (\_ _ m -> m)
|
2012-03-28 07:06:13 +00:00
|
|
|
}
|
2013-07-21 05:57:26 +00:00
|
|
|
, cipherHash = Hash
|
|
|
|
{ hashName = "const-hash"
|
|
|
|
, hashSize = 16
|
|
|
|
, hashF = (\_ -> B.replicate 16 1)
|
|
|
|
}
|
|
|
|
, cipherKeyExchange = CipherKeyExchange_RSA
|
|
|
|
, cipherMinVer = Nothing
|
|
|
|
}
|
2011-11-14 22:12:09 +00:00
|
|
|
|
2013-12-07 07:10:53 +00:00
|
|
|
blockCipherDHE_RSA :: Cipher
|
|
|
|
blockCipherDHE_RSA = blockCipher
|
|
|
|
{ cipherID = 0xff14
|
|
|
|
, cipherName = "dhe-rsa-id-const"
|
|
|
|
, cipherKeyExchange = CipherKeyExchange_DHE_RSA
|
|
|
|
}
|
|
|
|
|
2013-12-28 15:25:54 +00:00
|
|
|
blockCipherDHE_DSS :: Cipher
|
|
|
|
blockCipherDHE_DSS = blockCipher
|
|
|
|
{ cipherID = 0xff15
|
|
|
|
, cipherName = "dhe-dss-id-const"
|
|
|
|
, cipherKeyExchange = CipherKeyExchange_DHE_DSS
|
|
|
|
}
|
|
|
|
|
2013-12-07 07:10:53 +00:00
|
|
|
streamCipher :: Cipher
|
2011-12-11 20:43:32 +00:00
|
|
|
streamCipher = blockCipher
|
2013-07-21 05:57:26 +00:00
|
|
|
{ cipherID = 0xff13
|
|
|
|
, cipherBulk = Bulk
|
|
|
|
{ bulkName = "stream"
|
|
|
|
, bulkKeySize = 16
|
|
|
|
, bulkIVSize = 0
|
|
|
|
, bulkBlockSize = 0
|
|
|
|
, bulkF = BulkStreamF (\k -> k) (\i m -> (m,i)) (\i m -> (m,i))
|
2012-03-28 07:06:13 +00:00
|
|
|
}
|
2013-07-21 05:57:26 +00:00
|
|
|
}
|
2011-12-11 20:43:32 +00:00
|
|
|
|
2011-11-14 22:12:09 +00:00
|
|
|
supportedCiphers :: [Cipher]
|
2013-12-28 15:25:54 +00:00
|
|
|
supportedCiphers = [blockCipher,blockCipherDHE_RSA,blockCipherDHE_DSS,streamCipher]
|
2011-11-14 22:12:09 +00:00
|
|
|
|
|
|
|
supportedVersions :: [Version]
|
|
|
|
supportedVersions = [SSL3,TLS10,TLS11,TLS12]
|
|
|
|
|
|
|
|
arbitraryPairParams = do
|
2013-12-28 15:25:54 +00:00
|
|
|
(dsaPub, dsaPriv) <- (\(p,r) -> (PubKeyDSA p, PrivKeyDSA r)) <$> arbitraryDSAPair
|
|
|
|
let (pubKey, privKey) = (\(p, r) -> (PubKeyRSA p, PrivKeyRSA r)) $ getGlobalRSAPair
|
|
|
|
creds <- mapM (\(pub, priv) -> do
|
|
|
|
cert <- arbitraryX509WithKey (pub, priv)
|
|
|
|
return (CertificateChain [cert], priv)
|
|
|
|
) [ (pubKey, privKey), (dsaPub, dsaPriv) ]
|
2013-12-03 07:20:28 +00:00
|
|
|
connectVersion <- elements supportedVersions
|
|
|
|
let allowedVersions = [ v | v <- supportedVersions, v <= connectVersion ]
|
|
|
|
serAllowedVersions <- (:[]) `fmap` elements allowedVersions
|
|
|
|
serverCiphers <- arbitraryCiphers
|
|
|
|
clientCiphers <- oneof [arbitraryCiphers] `suchThat` (\cs -> or [x `elem` serverCiphers | x <- cs])
|
|
|
|
secNeg <- arbitrary
|
2012-03-28 07:06:13 +00:00
|
|
|
|
2013-12-28 15:25:54 +00:00
|
|
|
--let cred = (CertificateChain [servCert], PrivKeyRSA privKey)
|
2013-07-21 05:57:26 +00:00
|
|
|
let serverState = defaultParamsServer
|
2013-12-03 07:20:28 +00:00
|
|
|
{ pAllowedVersions = serAllowedVersions
|
2013-07-21 05:57:26 +00:00
|
|
|
, pCiphers = serverCiphers
|
2013-12-28 15:25:54 +00:00
|
|
|
, pCredentials = Credentials creds
|
2013-07-21 05:57:26 +00:00
|
|
|
, pUseSecureRenegotiation = secNeg
|
|
|
|
, pLogging = logging "server: "
|
2013-12-11 08:40:24 +00:00
|
|
|
, roleParams = roleParams $ updateServerParams (\sp -> sp { serverDHEParams = Just dhParams }) defaultParamsServer
|
2013-07-21 05:57:26 +00:00
|
|
|
}
|
|
|
|
let clientState = defaultParamsClient
|
2014-01-12 07:15:16 +00:00
|
|
|
{ pAllowedVersions = allowedVersions
|
2013-07-21 05:57:26 +00:00
|
|
|
, pCiphers = clientCiphers
|
|
|
|
, pUseSecureRenegotiation = secNeg
|
|
|
|
, pLogging = logging "client: "
|
|
|
|
}
|
|
|
|
return (clientState, serverState)
|
|
|
|
where
|
|
|
|
logging pre =
|
|
|
|
if debug
|
|
|
|
then defaultLogging { loggingPacketSent = putStrLn . ((pre ++ ">> ") ++)
|
|
|
|
, loggingPacketRecv = putStrLn . ((pre ++ "<< ") ++) }
|
|
|
|
else defaultLogging
|
|
|
|
arbitraryCiphers = resize (length supportedCiphers + 1) $ listOf1 (elements supportedCiphers)
|
2011-11-14 22:12:09 +00:00
|
|
|
|
2013-05-15 05:41:47 +00:00
|
|
|
setPairParamsSessionManager :: SessionManager -> (Params, Params) -> (Params, Params)
|
2012-07-12 07:59:59 +00:00
|
|
|
setPairParamsSessionManager manager (clientState, serverState) = (nc,ns)
|
2013-07-21 05:57:26 +00:00
|
|
|
where nc = setSessionManager manager clientState
|
|
|
|
ns = setSessionManager manager serverState
|
2011-12-20 07:48:19 +00:00
|
|
|
|
2012-07-12 08:02:10 +00:00
|
|
|
setPairParamsSessionResuming sessionStuff (clientState, serverState) = (nc,serverState)
|
2013-07-21 05:57:26 +00:00
|
|
|
where nc = updateClientParams (\cparams -> cparams { clientWantSessionResume = Just sessionStuff }) clientState
|
2011-12-20 07:48:19 +00:00
|
|
|
|
2011-11-14 22:12:09 +00:00
|
|
|
newPairContext pipe (cParams, sParams) = do
|
2013-07-21 05:57:26 +00:00
|
|
|
let noFlush = return ()
|
|
|
|
let noClose = return ()
|
2011-11-14 22:12:09 +00:00
|
|
|
|
2013-07-21 05:57:26 +00:00
|
|
|
cRNG <- RNG.makeSystem
|
|
|
|
sRNG <- RNG.makeSystem
|
2011-11-14 22:12:09 +00:00
|
|
|
|
2013-07-21 05:57:26 +00:00
|
|
|
let cBackend = Backend noFlush noClose (writePipeA pipe) (readPipeA pipe)
|
|
|
|
let sBackend = Backend noFlush noClose (writePipeB pipe) (readPipeB pipe)
|
|
|
|
cCtx' <- contextNew cBackend cParams cRNG
|
|
|
|
sCtx' <- contextNew sBackend sParams sRNG
|
2011-11-14 22:12:09 +00:00
|
|
|
|
2013-07-21 05:57:26 +00:00
|
|
|
return (cCtx', sCtx')
|
2013-07-21 06:37:58 +00:00
|
|
|
|
|
|
|
establishDataPipe params tlsServer tlsClient = do
|
|
|
|
-- initial setup
|
|
|
|
pipe <- newPipe
|
|
|
|
_ <- (runPipe pipe)
|
|
|
|
startQueue <- newChan
|
|
|
|
resultQueue <- newChan
|
|
|
|
|
|
|
|
(cCtx, sCtx) <- newPairContext pipe params
|
|
|
|
|
|
|
|
_ <- forkIO $ E.catch (tlsServer sCtx resultQueue) (printAndRaise "server")
|
|
|
|
_ <- forkIO $ E.catch (tlsClient startQueue cCtx) (printAndRaise "client")
|
|
|
|
|
|
|
|
return (startQueue, resultQueue)
|
|
|
|
where
|
|
|
|
printAndRaise :: String -> E.SomeException -> IO ()
|
|
|
|
printAndRaise s e = putStrLn (s ++ " exception: " ++ show e) >> E.throw e
|