2014-09-14 2 views
1

Возможно, я просто пропустил что-то основное в документации http-client-tls и tls, но: как я могу установить HTTPS-соединение с сервером и принимать только один конкретный сертификат, указанный мной, который потенциально не входит в систему магазин сертификатов?Принимать конкретный сертификат с помощью http-client-tls или tls?

ответ

0

Я вижу, что это старый вопрос, но я просто потратил некоторое время на создание кода, чтобы сделать это, и решил, что я отправлю его сюда для потомков ... и в надежде получить от него обзор кода. Комментарий 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) вы можете загрузить систему магазина, используя getSystemCertificateStore из System.X509, а затем использовать Data.X509.CertificateStore конвертировать туда и обратно между CertificateStore и [SignedCertificate] создать магазин с сертификатами системы вместе с вашими собственными.
  • TLS.defaultParamsClient принимает имя хоста и идентификатор сервера, используемый для обозначения имени сервера TLS (SNI), расширение TLS, которое позволяет серверу размещать несколько сайтов на одном IP-адресе (подобно тому, как работают заголовки хостов HTTP/1.1). Мы не обязательно знаем, как это установить, когда мы создаем менеджера. К счастью, Network.Connection (используется http-client-tls) отображается override whatever settings we use, так что это не имеет значения.
  • По умолчанию для TLS.supportedCiphers является пустым списком, поэтому этот параметр требуется (если вы не отключите проверку или что-то еще). Network.Connectiondefaults to ciphersuite_all, но это включает в себя некоторые «не рекомендованные последние списки шифрования ресурсов», поэтому я решил использовать вместо этого ciphersuite_default.
Смежные вопросы