change related to the new certificatestore.

This commit is contained in:
Vincent Hanquez 2012-10-16 08:40:40 +01:00
parent b125a04215
commit 12a28a833a
6 changed files with 21 additions and 44 deletions

View file

@ -3,12 +3,11 @@
import Network.TLS import Network.TLS
import Network.TLS.Extra import Network.TLS.Extra
import Data.Char
import Data.IORef import Data.IORef
import Data.Time.Clock import Data.Time.Clock
import Data.Certificate.X509 import Data.Certificate.X509
import System.Certificate.X509
import System.IO
import Control.Monad import Control.Monad
import qualified Crypto.Random.AESCtr as RNG import qualified Crypto.Random.AESCtr as RNG
@ -77,9 +76,10 @@ main = do
showCert (output a) $ head certs showCert (output a) $ head certs
when (verify a) $ do when (verify a) $ do
store <- getSystemCertificateStore
putStrLn "### certificate chain trust" putStrLn "### certificate chain trust"
ctime <- utctDay `fmap` getCurrentTime ctime <- utctDay `fmap` getCurrentTime
certificateVerifyChain certs >>= showUsage "chain validity" certificateVerifyChain store certs >>= showUsage "chain validity"
showUsage "time validity" (certificateVerifyValidity ctime certs) showUsage "time validity" (certificateVerifyValidity ctime certs)
when (verifyFQDN a /= "") $ when (verifyFQDN a /= "") $
showUsage "fqdn match" (certificateVerifyDomain (verifyFQDN a) certs) showUsage "fqdn match" (certificateVerifyDomain (verifyFQDN a) certs)

View file

@ -10,6 +10,7 @@ import qualified Data.ByteString.Lazy.Char8 as LC
import Control.Exception import Control.Exception
import qualified Control.Exception as E import qualified Control.Exception as E
import System.Environment import System.Environment
import System.Certificate.X509
import Data.IORef import Data.IORef
@ -43,7 +44,7 @@ instance SessionManager SessionRef where
sessionResume (SessionRef ref) sid = readIORef ref >>= \(s,d) -> if s == sid then return (Just d) else return Nothing sessionResume (SessionRef ref) sid = readIORef ref >>= \(s,d) -> if s == sid then return (Just d) else return Nothing
sessionInvalidate _ _ = return () sessionInvalidate _ _ = return ()
getDefaultParams sStorage session = updateClientParams setCParams $ setSessionManager (SessionRef sStorage) $ defaultParams getDefaultParams store sStorage session = updateClientParams setCParams $ setSessionManager (SessionRef sStorage) $ defaultParamsClient
{ pConnectVersion = TLS10 { pConnectVersion = TLS10
, pAllowedVersions = [TLS10,TLS11,TLS12] , pAllowedVersions = [TLS10,TLS11,TLS12]
, pCiphers = ciphers , pCiphers = ciphers
@ -57,7 +58,7 @@ getDefaultParams sStorage session = updateClientParams setCParams $ setSessionMa
{ loggingPacketSent = putStrLn . ("debug: >> " ++) { loggingPacketSent = putStrLn . ("debug: >> " ++)
, loggingPacketRecv = putStrLn . ("debug: << " ++) , loggingPacketRecv = putStrLn . ("debug: << " ++)
} }
crecv = if validateCert then certificateVerifyChain else (\_ -> return CertificateUsageAccept) crecv = if validateCert then certificateVerifyChain store else (\_ -> return CertificateUsageAccept)
main = do main = do
@ -65,7 +66,8 @@ main = do
args <- getArgs args <- getArgs
let hostname = args !! 0 let hostname = args !! 0
let port = read (args !! 1) :: Int let port = read (args !! 1) :: Int
runTLS (getDefaultParams sStorage Nothing) hostname (fromIntegral port) $ \ctx -> do store <- getSystemCertificateStore
runTLS (getDefaultParams store sStorage Nothing) hostname (fromIntegral port) $ \ctx -> do
handshake ctx handshake ctx
sendData ctx $ LC.pack "GET / HTTP/1.0\r\n\r\n" sendData ctx $ LC.pack "GET / HTTP/1.0\r\n\r\n"
d <- recvData' ctx d <- recvData' ctx

View file

@ -5,6 +5,7 @@ import Network.Socket
import System.IO import System.IO
import System.IO.Error (isEOFError) import System.IO.Error (isEOFError)
import System.Console.CmdArgs import System.Console.CmdArgs
import System.Certificate.X509
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
@ -199,7 +200,8 @@ doClient pargs = do
, loggingPacketRecv = putStrLn . ("debug: recv: " ++) , loggingPacketRecv = putStrLn . ("debug: recv: " ++)
} }
let crecv = if validCert pargs then certificateVerifyChain else (\_ -> return CertificateUsageAccept) store <- getSystemCertificateStore
let crecv = if validCert pargs then certificateVerifyChain store else (\_ -> return CertificateUsageAccept)
let clientstate = defaultParamsClient let clientstate = defaultParamsClient
{ pConnectVersion = TLS10 { pConnectVersion = TLS10
, pAllowedVersions = [TLS10,TLS11,TLS12] , pAllowedVersions = [TLS10,TLS11,TLS12]

View file

@ -20,7 +20,6 @@ import Control.Applicative ((<$>))
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import Data.Certificate.X509 import Data.Certificate.X509
import System.Certificate.X509 as SysCert
-- for signing/verifying certificate -- for signing/verifying certificate
import qualified Crypto.Hash.SHA1 as SHA1 import qualified Crypto.Hash.SHA1 as SHA1
@ -29,6 +28,7 @@ import qualified Crypto.Hash.MD5 as MD5
import qualified Crypto.Cipher.RSA as RSA import qualified Crypto.Cipher.RSA as RSA
import qualified Crypto.Cipher.DSA as DSA import qualified Crypto.Cipher.DSA as DSA
import Data.CertificateStore
import Data.Certificate.X509.Cert (oidCommonName) import Data.Certificate.X509.Cert (oidCommonName)
import Network.TLS (CertificateUsage(..), CertificateRejectReason(..)) import Network.TLS (CertificateUsage(..), CertificateRejectReason(..))
@ -36,39 +36,17 @@ import Data.Time.Calendar
import Data.List (find) import Data.List (find)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
#if defined(NOCERTVERIFY)
import System.IO (hPutStrLn, stderr)
#endif
-- | Returns 'CertificateUsageAccept' if all the checks pass, or the first -- | Returns 'CertificateUsageAccept' if all the checks pass, or the first
-- failure. -- failure.
certificateChecks :: [ [X509] -> IO CertificateUsage ] -> [X509] -> IO CertificateUsage certificateChecks :: [ [X509] -> IO CertificateUsage ] -> [X509] -> IO CertificateUsage
certificateChecks checks x509s = certificateChecks checks x509s =
fromMaybe CertificateUsageAccept . find (CertificateUsageAccept /=) <$> mapM ($ x509s) checks fromMaybe CertificateUsageAccept . find (CertificateUsageAccept /=) <$> mapM ($ x509s) checks
#if defined(NOCERTVERIFY) certificateVerifyChain_ :: CertificateStore -> [X509] -> IO CertificateUsage
certificateVerifyChain_ _ [] = return $ CertificateUsageReject (CertificateRejectOther "empty chain / no certificates")
# warning "********certificate verify chain doesn't yet work on your platform *************" certificateVerifyChain_ store (x:xs) = do
# warning "********please consider contributing to the certificate to fix this issue *************"
# warning "********getting trusted system certificate is platform dependant *************"
{- on windows and OSX, the trusted certificates are not yet accessible,
- for now, print a big fat warning (better than nothing) and returns true -}
certificateVerifyChain_ :: [X509] -> IO CertificateUsage
certificateVerifyChain_ _ = do
hPutStrLn stderr "****************** certificate verify chain doesn't yet work on your platform **********************"
hPutStrLn stderr "please consider contributing to the certificate package to fix this issue"
return CertificateUsageAccept
#else
certificateVerifyChain_ :: [X509] -> IO CertificateUsage
certificateVerifyChain_ [] = return $ CertificateUsageReject (CertificateRejectOther "empty chain / no certificates")
certificateVerifyChain_ (x:xs) = do
-- find a matching certificate that we trust (== installed on the system) -- find a matching certificate that we trust (== installed on the system)
foundCert <- SysCert.findCertificate (certMatchDN x) case findCertificate (certIssuerDN $ x509Cert x) store of
case foundCert of
Just sysx509 -> do Just sysx509 -> do
validChain <- certificateVerifyAgainst x sysx509 validChain <- certificateVerifyAgainst x sysx509
if validChain if validChain
@ -79,9 +57,8 @@ certificateVerifyChain_ (x:xs) = do
_ -> do _ -> do
validChain <- certificateVerifyAgainst x (head xs) validChain <- certificateVerifyAgainst x (head xs)
if validChain if validChain
then certificateVerifyChain_ xs then certificateVerifyChain_ store xs
else return $ CertificateUsageReject (CertificateRejectOther "chain doesn't match each other") else return $ CertificateUsageReject (CertificateRejectOther "chain doesn't match each other")
#endif
-- | verify a certificates chain using the system certificates available. -- | verify a certificates chain using the system certificates available.
-- --
@ -97,8 +74,8 @@ certificateVerifyChain_ (x:xs) = do
-- --
-- TODO: verify validity, check revocation list if any, add optional user output to know -- TODO: verify validity, check revocation list if any, add optional user output to know
-- the rejection reason. -- the rejection reason.
certificateVerifyChain :: [X509] -> IO CertificateUsage certificateVerifyChain :: CertificateStore -> [X509] -> IO CertificateUsage
certificateVerifyChain = certificateVerifyChain_ . reorderList certificateVerifyChain store = certificateVerifyChain_ store . reorderList
where where
reorderList [] = [] reorderList [] = []
reorderList (x:xs) = reorderList (x:xs) =
@ -158,7 +135,7 @@ rsaVerify h hdesc pk a b = either (Left . show) (Right) $ RSA.verify h hdesc pk
certificateVerifyDomain :: String -> [X509] -> CertificateUsage certificateVerifyDomain :: String -> [X509] -> CertificateUsage
certificateVerifyDomain _ [] = CertificateUsageReject (CertificateRejectOther "empty list") certificateVerifyDomain _ [] = CertificateUsageReject (CertificateRejectOther "empty list")
certificateVerifyDomain fqhn (X509 cert _ _ _ _:_) = certificateVerifyDomain fqhn (X509 cert _ _ _ _:_) =
let names = maybe [] ((:[]) . snd) (lookup oidCommonName $ certSubjectDN cert) let names = maybe [] ((:[]) . snd) (lookup oidCommonName $ getDistinguishedElements $ certSubjectDN cert)
++ maybe [] (maybe [] toAltName . extensionGet) (certExtensions cert) in ++ maybe [] (maybe [] toAltName . extensionGet) (certExtensions cert) in
orUsage $ map (matchDomain . splitDot) names orUsage $ map (matchDomain . splitDot) names
where where

View file

@ -12,7 +12,7 @@ import Data.Time.Clock (secondsToDiffTime)
readableChar :: Gen Char readableChar :: Gen Char
readableChar = elements (['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']) readableChar = elements (['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'])
arbitraryDN = return [] arbitraryDN = return $ X509Cert.DistinguishedName []
arbitraryTime = do arbitraryTime = do
year <- choose (1951, 2050) year <- choose (1951, 2050)

View file

@ -44,8 +44,6 @@ Library
Network.TLS.Extra.Thread Network.TLS.Extra.Thread
Network.TLS.Extra.File Network.TLS.Extra.File
ghc-options: -Wall -fno-warn-missing-signatures ghc-options: -Wall -fno-warn-missing-signatures
if os(windows)
cpp-options: -DNOCERTVERIFY
if os(linux) && flag(fastaes) && (arch(i386) || arch(x86_64)) if os(linux) && flag(fastaes) && (arch(i386) || arch(x86_64))
cpp-options: -DCIPHER_AES cpp-options: -DCIPHER_AES
Build-Depends: cipher-aes >= 0.1 && < 0.2 Build-Depends: cipher-aes >= 0.1 && < 0.2
@ -61,8 +59,6 @@ executable Tests
, cprng-aes >= 0.2.3 , cprng-aes >= 0.2.3
else else
Buildable: False Buildable: False
if os(windows)
cpp-options: -DNOCERTVERIFY
if os(linux) && flag(fastaes) if os(linux) && flag(fastaes)
cpp-options: -DCIPHER_AES cpp-options: -DCIPHER_AES
Build-Depends: cipher-aes >= 0.1 && < 0.2 Build-Depends: cipher-aes >= 0.1 && < 0.2