我可能只是忽略了http-client-tls和tls文档中的基本内容,但是:如何建立与服务器的HTTPS连接并且只接受一个特定的<我指定的/ em>证书,可能不在系统证书存储区中?
答案 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.CertificateStore
在CertificateStore
和[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
。