-- | -- Module : System.Certificate.X509 -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : unix only -- -- this module is portable to unix system where there is usually -- a /etc/ssl/certs with system X509 certificates. -- -- the path can be dynamically override using the environment variable -- defined by envPathOverride in the module, which by -- default is SYSTEM_CERTIFICATE_PATH -- module System.Certificate.X509.Unix ( getSystemCertificateStore ) where import System.Directory (getDirectoryContents, doesFileExist) import System.Environment (getEnv) import System.FilePath (()) import Data.List (isPrefixOf) import Data.PEM (PEM(..), pemParseBS) import Data.Either import Data.Certificate.X509 import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L import Data.CertificateStore import Control.Applicative ((<$>)) import Control.Monad (filterM) import qualified Control.Exception as E import Data.Char defaultSystemPath :: FilePath defaultSystemPath = "/etc/ssl/certs/" envPathOverride :: String envPathOverride = "SYSTEM_CERTIFICATE_PATH" listDirectoryCerts :: FilePath -> IO [FilePath] listDirectoryCerts path = (map (path ) . filter isCert <$> getDirectoryContents path) >>= filterM doesFileExist where isHashedFile s = length s == 10 && isDigit (s !! 9) && (s !! 8) == '.' && all isHexDigit (take 8 s) isCert x = (not $ isPrefixOf "." x) && (not $ isHashedFile x) getSystemCertificateStore :: IO CertificateStore getSystemCertificateStore = makeCertificateStore . concat <$> (getSystemPath >>= listDirectoryCerts >>= mapM readCertificates) getSystemPath :: IO FilePath getSystemPath = E.catch (getEnv envPathOverride) inDefault where inDefault :: E.IOException -> IO FilePath inDefault _ = return defaultSystemPath readCertificates :: FilePath -> IO [X509] readCertificates file = E.catch (either (const []) (rights . map getCert) . pemParseBS <$> B.readFile file) skipIOError where getCert pem = decodeCertificate $ L.fromChunks [pemContent pem] skipIOError :: E.IOException -> IO [X509] skipIOError _ = return []