{-# LANGUAGE CPP #-} -- Disable this warning so we can still test deprecated functionality. {-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} module Common ( printCiphers, printDHParams, printGroups, readNumber, readCiphers, readDHParams, readGroups, printHandshakeInfo, makeAddrInfo, AddrInfo (..), getCertificateStore, ) where import Data.Char (isDigit) import Network.Socket import Numeric (showHex) import Crypto.System.CPU import Data.X509.CertificateStore import System.X509 import Network.TLS hiding (HostName) import Network.TLS.Extra.Cipher import Network.TLS.Extra.FFDHE import Imports namedDHParams :: [(String, DHParams)] namedDHParams = [ ("ffdhe2048", ffdhe2048) , ("ffdhe3072", ffdhe3072) , ("ffdhe4096", ffdhe4096) , ("ffdhe6144", ffdhe6144) , ("ffdhe8192", ffdhe8192) ] namedCiphersuites :: [(String, [CipherID])] namedCiphersuites = [ ("all", map cipherID ciphersuite_all) , ("default", map cipherID ciphersuite_default) , ("strong", map cipherID ciphersuite_strong) ] namedGroups :: [(String, Group)] namedGroups = [ ("ffdhe2048", FFDHE2048) , ("ffdhe3072", FFDHE3072) , ("ffdhe4096", FFDHE4096) , ("ffdhe6144", FFDHE6144) , ("ffdhe8192", FFDHE8192) , ("p256", P256) , ("p384", P384) , ("p521", P521) , ("x25519", X25519) , ("x448", X448) ] readNumber :: (Num a, Read a) => String -> Maybe a readNumber s | all isDigit s = Just $ read s | otherwise = Nothing readCiphers :: String -> Maybe [CipherID] readCiphers s = case lookup s namedCiphersuites of Nothing -> (: []) `fmap` readNumber s just -> just readDHParams :: String -> IO (Maybe DHParams) readDHParams s = case lookup s namedDHParams of Nothing -> (Just . read) `fmap` readFile s mparams -> return mparams readGroups :: String -> Maybe [Group] readGroups s = traverse (`lookup` namedGroups) (split ',' s) printCiphers :: IO () printCiphers = do putStrLn "Supported ciphers" putStrLn "=====================================" forM_ ciphersuite_all_det $ \c -> putStrLn ( pad 50 (cipherName c) ++ " = " ++ pad 5 (show $ cipherID c) ++ " 0x" ++ showHex (cipherID c) "" ) putStrLn "" putStrLn "Ciphersuites" putStrLn "=====================================" forM_ namedCiphersuites $ \(name, _) -> putStrLn name putStrLn "" putStrLn ("Using crypton-" ++ VERSION_crypton ++ " with CPU support for: " ++ cpuSupport) where pad n s | length s < n = s ++ replicate (n - length s) ' ' | otherwise = s cpuSupport | null processorOptions = "(nothing)" | otherwise = intercalate ", " (map show processorOptions) printDHParams :: IO () printDHParams = do putStrLn "DH Parameters" putStrLn "=====================================" forM_ namedDHParams $ \(name, _) -> putStrLn name putStrLn "(or /path/to/dhparams)" printGroups :: IO () printGroups = do putStrLn "Groups" putStrLn "=====================================" forM_ namedGroups $ \(name, _) -> putStrLn name printHandshakeInfo :: Context -> IO () printHandshakeInfo ctx = do info <- contextGetInformation ctx case info of Nothing -> return () Just i -> do putStrLn ("version: " ++ show (infoVersion i)) putStrLn ("cipher: " ++ show (infoCipher i)) putStrLn ("compression: " ++ show (infoCompression i)) putStrLn ("group: " ++ maybe "(none)" show (infoSupportedGroup i)) when (infoVersion i < TLS13) $ do putStrLn ("extended master secret: " ++ show (infoExtendedMainSecret i)) putStrLn ("resumption: " ++ show (infoTLS12Resumption i)) when (infoVersion i == TLS13) $ do putStrLn ("handshake emode: " ++ show (fromJust (infoTLS13HandshakeMode i))) putStrLn ("early data accepted: " ++ show (infoIsEarlyDataAccepted i)) sni <- getClientSNI ctx case sni of Nothing -> return () Just n -> putStrLn ("server name indication: " ++ n) makeAddrInfo :: Maybe HostName -> PortNumber -> IO AddrInfo makeAddrInfo maddr port = do let flgs = [AI_ADDRCONFIG, AI_NUMERICSERV, AI_PASSIVE] hints = defaultHints { addrFlags = flgs , addrSocketType = Stream } head <$> getAddrInfo (Just hints) maddr (Just $ show port) split :: Char -> String -> [String] split _ "" = [] split c s = case break (c ==) s of ("", r) -> split c (tail r) (s', "") -> [s'] (s', r) -> s' : split c (tail r) getCertificateStore :: [FilePath] -> IO CertificateStore getCertificateStore [] = getSystemCertificateStore getCertificateStore paths = foldM readPathAppend mempty paths where readPathAppend acc path = do mstore <- readCertificateStore path case mstore of Nothing -> error ("invalid certificate store: " ++ path) Just st -> return $! mappend st acc