{-# LANGUAGE BangPatterns #-} module Main where import Certificate import Control.Concurrent.Chan import Data.Default (def) import Data.IORef import Data.X509 import Data.X509.Validation import Test.Tasty.Bench import Network.TLS import Network.TLS.Extra.Cipher import Session import Run import PubKey import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L blockCipher :: Cipher blockCipher = Cipher { cipherID = 0xff12 , cipherName = "rsa-id-const" , cipherBulk = Bulk { bulkName = "id" , bulkKeySize = 16 , bulkIVSize = 16 , bulkExplicitIV = 0 , bulkAuthTagLen = 0 , bulkBlockSize = 16 , bulkF = BulkBlockF $ \_ _ _ m -> (m, B.empty) } , cipherHash = MD5 , cipherPRFHash = Nothing , cipherKeyExchange = CipherKeyExchange_RSA , cipherMinVer = Nothing } getParams :: Version -> Cipher -> (ClientParams, ServerParams) getParams connectVer cipher = (cParams, sParams) where sParams = def { serverSupported = supported , serverShared = def { sharedCredentials = Credentials [(CertificateChain [simpleX509 $ PubKeyRSA pubKey], PrivKeyRSA privKey)] } } cParams = (defaultParamsClient "" B.empty) { clientSupported = supported , clientShared = def { sharedValidationCache = ValidationCache { cacheAdd = \_ _ _ -> return () , cacheQuery = \_ _ _ -> return ValidationCachePass } } } supported = def { supportedCiphers = [cipher] , supportedVersions = [connectVer] , supportedGroups = [X25519, FFDHE2048] } (pubKey, privKey) = getGlobalRSAPair runTLSPipe :: (ClientParams, ServerParams) -> (Context -> Chan b -> IO ()) -> (Chan a -> Context -> IO ()) -> a -> IO b runTLSPipe params tlsServer tlsClient d = do withDataPipe params tlsServer tlsClient $ \(writeStart, readResult) -> do writeStart d readResult runTLSPipeSimple :: (ClientParams, ServerParams) -> B.ByteString -> IO B.ByteString runTLSPipeSimple params = runTLSPipe params tlsServer tlsClient where tlsServer ctx queue = do handshake ctx d <- recvData ctx writeChan queue d bye ctx tlsClient queue ctx = do handshake ctx d <- readChan queue sendData ctx (L.fromChunks [d]) byeBye ctx benchConnection :: (ClientParams, ServerParams) -> B.ByteString -> String -> Benchmark benchConnection params !d name = bench name . nfIO $ runTLSPipeSimple params d benchResumption :: (ClientParams, ServerParams) -> B.ByteString -> String -> Benchmark benchResumption params !d name = env initializeSession runResumption where initializeSession = do sessionRefs <- twoSessionRefs let sessionManagers = twoSessionManagers sessionRefs params1 = setPairParamsSessionManagers sessionManagers params _ <- runTLSPipeSimple params1 d Just sessionParams <- readClientSessionRef sessionRefs let params2 = setPairParamsSessionResuming sessionParams params1 newIORef params2 runResumption paramsRef = bench name . nfIO $ do params2 <- readIORef paramsRef runTLSPipeSimple params2 d benchResumption13 :: (ClientParams, ServerParams) -> B.ByteString -> String -> Benchmark benchResumption13 params !d name = env initializeSession runResumption where initializeSession = do sessionRefs <- twoSessionRefs let sessionManagers = twoSessionManagers sessionRefs params1 = setPairParamsSessionManagers sessionManagers params _ <- runTLSPipeSimple params1 d newIORef (params1, sessionRefs) -- with TLS13 the sessionId is constantly changing so we must update -- our parameters at each iteration unfortunately runResumption paramsRef = bench name . nfIO $ do (params1, sessionRefs) <- readIORef paramsRef Just sessionParams <- readClientSessionRef sessionRefs let params2 = setPairParamsSessionResuming sessionParams params1 runTLSPipeSimple params2 d benchCiphers :: String -> Version -> B.ByteString -> [Cipher] -> Benchmark benchCiphers name connectVer d = bgroup name . map doBench where doBench cipher = benchResumption13 (getParams connectVer cipher) d (cipherName cipher) main :: IO () main = defaultMain [ bgroup "connection" -- not sure the number actually make sense for anything. improve .. [ benchConnection (getParams TLS12 blockCipher) small "TLS12-256 bytes" ] , bgroup "resumption" [ benchResumption (getParams TLS12 blockCipher) small "TLS12-256 bytes" ] , -- Here we try to measure TLS12 and TLS13 performance with AEAD ciphers. -- Resumption and a larger message can be a demonstration of the symmetric -- crypto but for TLS13 this does not work so well because of dhe_psk. benchCiphers "TLS12" TLS12 large [ cipher_DHE_RSA_WITH_AES_128_GCM_SHA256 , cipher_DHE_RSA_WITH_AES_256_GCM_SHA384 , cipher_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 , cipher_ECDHE_RSA_WITH_AES_128_GCM_SHA256 , cipher_ECDHE_RSA_WITH_AES_256_GCM_SHA384 , cipher_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 ] , benchCiphers "TLS13" TLS13 large [ cipher13_AES_128_GCM_SHA256 , cipher13_AES_256_GCM_SHA384 , cipher13_CHACHA20_POLY1305_SHA256 , cipher13_AES_128_CCM_SHA256 , cipher13_AES_128_CCM_8_SHA256 ] ] where small = B.replicate 256 0 large = B.replicate 102400 0