使用http-client-tls或tls接受特定证书?

时间:2014-09-14 12:39:25

标签: haskell ssl certificate

我可能只是忽略了http-client-tlstls文档中的基本内容,但是:如何建立与服务器的HTTPS连接并且只接受一个特定的<我指定的/ em>证书,可能不在系统证书存储区中?

2 个答案:

答案 0 :(得分:4)

我认为您正在寻找ClientHooks。您可以使用TLSSettings构造函数创建TLSSettings值,然后使用mkManagerSettings创建ManagerSettings

答案 1 :(得分:4)

我看到这是一个老问题,但我只是花了一些时间编写代码来做这件事,并认为我在这里发布它是为了后代...并希望从社区获得一些代码审查。 Snoyman的评论是有帮助的,但是这里有很多代码相互依赖,X.509和TLS是如此沸腾的海洋,它很难调试并且确定你知道你的如果不深入挖掘各种库,就不要搞砸了。我认为工作代码的顺序更完整。

无论如何,这是我提出的问题(这是一个stack script所以你可以自己轻松地运行它) -

#!/usr/bin/env stack
{- stack --resolver lts-7.16 runghc -}

import qualified Data.ByteString           as B
import           Data.ByteString.Lazy         (ByteString)
import           Data.Default.Class           (def)
import           Data.String                  (fromString)
import           Data.X509.CertificateStore   (CertificateStore, readCertificateStore)
import           Network.HTTP.Client          (httpLbs, newManager, ManagerSettings)
import           Network.HTTP.Client.TLS      (mkManagerSettings)
import           Network.Connection           (TLSSettings(TLSSettings))
import qualified Network.TLS               as TLS
import qualified Network.TLS.Extra.Cipher  as TLS
import           System.Environment           (getArgs, getProgName)

managerSettings :: CertificateStore -> ManagerSettings
managerSettings store = mkManagerSettings settings Nothing
  where settings = TLSSettings params
        params   = (TLS.defaultParamsClient "" B.empty) {
                       TLS.clientUseServerNameIndication = True
                     , TLS.clientShared = def {
                           TLS.sharedCAStore = store
                       }
                     , TLS.clientSupported = def {
                           TLS.supportedCiphers = TLS.ciphersuite_default
                       }
                   }

get :: FilePath -> String -> IO ()
get ca url = do
    mstore <- readCertificateStore ca
    case mstore of
        Just store -> do
            manager  <- newManager $ managerSettings store
            response <- httpLbs (fromString url) manager
            putStrLn (show response)
        Nothing    -> do
            putStrLn $ "error: invalid certificate store " ++ ca

main :: IO ()
main = do
    args <- getArgs
    case args of
        ca:url:[] -> get ca url
        _         -> do
            name <- getProgName
            putStrLn $ "usage: " ++ name ++ " ca url"

一对夫妇注意到:

  • TLS.sharedCAStore设置是神奇发生的地方。如果您希望 CA添加到系统存储区(而不是仅使用 CA),则可以使用System.X509中的getSystemCertificateStore加载系统存储区。然后使用Data.X509.CertificateStoreCertificateStore[SignedCertificate]之间来回转换,以创建一个包含系统证书的商店。
  • TLS.defaultParamsClient获取主机名和服务器ID,用于TLS服务器名称指示(SNI),TLS扩展允许服务器在单个IP上托管多个站点(类似于HTTP / 1.1主机头的工作方式) )。当我们创建经理时,我们不一定知道该怎么做。幸运的是,Network.Connection(由http-client-tls使用)似乎override whatever settings we use,所以它并不重要。
  • TLS.supportedCiphers的默认值为空列表,因此需要此设置(除非您关闭验证或其他内容)。 Network.Connection defaults to ciphersuite_all但其中包含一些&#34;不推荐的最后一个资源密码套件&#34;所以我选择使用ciphersuite_default