Как заставить CRL и OSCP Checking работать на iOS?

9

Я не могу заставить CRL работать на iOS. Я создал два теста. У меня есть действующий сертификат, выданный центром сертификации. У меня есть еще один действительный сертификат, выданный ЦС, но ЦС добавил этот сертификат в свой CRL.

Затем я настраиваю политику отзыва, которая включает проверку CRL и требует, чтобы она прошла успешно.

func crlValidationTest(trustedCert: SecCertificate, certToVerify: SecCertificate) -> Bool {

    let basicPolicy = SecPolicyCreateBasicX509()

    let crlPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod | kSecRevocationCRLMethod | kSecRevocationRequirePositiveResponse)!

    var trust: SecTrust?

    SecTrustCreateWithCertificates(NSArray(object: certToVerify), NSArray(objects: basicPolicy, crlPolicy), &trust)
    SecTrustSetAnchorCertificates(trust!, NSArray(object: trustedCert))
    SecTrustSetNetworkFetchAllowed(trust!, true)

    var trustResult = SecTrustResultType.invalid

    guard SecTrustEvaluate(trust!, &trustResult) == errSecSuccess else {
        return false
    }

    return trustResult == SecTrustResultType.proceed || trustResult == SecTrustResultType.unspecified
}

Я ожидаю, что сертификат, который находится в CRL, будет ненадежным, а чистый сертификат будет доверенным.

Учитывая вышеупомянутую конфигурацию, оба терпят неудачу как недоверенные. Если я уберу kSecRevocationRequirePositiveResponseфлаг, оба удастся. Я попробовал все различные варианты использования только OSCP или только CRL, и ничего не работает так, как я ожидал.

Яблочная документация для SecPolicyCreateRevocationштатов:

Как правило, нет необходимости создавать политику отзыва самостоятельно, если вы не хотите переопределять поведение системы по умолчанию, например, для принудительного использования определенного метода или полного отключения проверки отзыва.

Использование только SecPolicyCreateBasicX509политики позволяет успешно выполнять оба действия (когда должен произойти сбой второго сертификата), поэтому поведение Apple по умолчанию вообще не выполняет проверку CRL?

Я подключил CharlesProxy к своему устройству и запускал код несколько раз, прослушивая весь сетевой трафик, и никакие исходящие запросы никогда не отправлялись в CRL, что объясняет, почему все не работают, когда установлен RequirePositiveResponseфлажок.

Я также попытался перейти непосредственно с устройства на CRL, используя URLRequest, и смог получить данные CRL на устройстве без каких-либо проблем.

Проверка CRL не поддерживается через библиотеку Apple Security? Если это так, кто-нибудь выяснил конфигурацию, чтобы заставить его правильно реагировать? Какие альтернативы используются для проверки CRL, я предполагаю, что мобильные приложения с высоким уровнем безопасности, работающие в финансовом районе или в других уязвимых областях, не позволят создать этот пробел.

ОБНОВЛЕНИЕ Для сравнения я запустилcertutil -f -urlfetch -verify MYCERT.cercertutil и прикрепил Fiddler к коробке с командой. Я получаю ожидаемые результаты, которые iOS не дает мне, и я вижу исходящий запрос к CRL через HTTP через fiddler.

Я создал щедрость, чтобы вызвать интерес к этому. Я надеюсь, что у кого-то есть больше деталей относительно того, что делается неправильно, или почему это не работает на iOS.

Unome
источник

Ответы:

7

На платформах Apple клиенты не проверяют список отзыва сертификатов (CRL) CA и не используют OCSP по умолчанию.

Платформы Apple, однако, поддерживают сшивание OCSP и, в качестве альтернативы, предоставляют механизм, который они называют Revocation Enhancement, который действительно может привести к вызову OCSP, см. Подробности ниже.

OCSP Сшивание

Сначала объяснение сшивания OCSP:

Статус Online Certificate Protocol (OCSP) сшивание , официально известное как запрос статуса TLS сертификат расширение, является стандартом для проверки состояния аннулирования X.509 цифровых сертификатов. 1 Он позволяет предъявителю сертификата нести затраты на ресурсы, связанные с предоставлением ответов протокола OCSP, путем добавления («сшивания») ответа OCSP с меткой времени, подписанного СА, к первоначальному рукопожатию TLS, что устраняет необходимость для клиентов, чтобы связаться с CA, с целью улучшения как безопасности, так и производительности.

см. https://en.wikipedia.org/wiki/OCSP_stapling

Различия между OCSP и OCSP Stapling

Если клиент подключается к серверу в традиционном потоке OCSP и получает сертификат, он проверяет, был ли отозван полученный сертификат, отправив запрос в ЦС. Это имеет некоторые недостатки, например, требуется дополнительное сетевое соединение, информация не зашифрована и, следовательно, представляет проблему конфиденциальности данных.

Посредством сшивания OCSP сервер запрашивает подписанную информацию об отзыве у ЦС и добавляет ее в квитирование TLS.

Это также означает, что при использовании сшивания OCSP вы не видите запрос OCSP от iOS к серверу CA.

Недостатки сшивания OCSP

Сервер, к которому вы подключаетесь, должен поддерживать сшивание OCSP. Это также не защищает от вредоносных серверов.

Это основные причины, по которым Apple предоставляет улучшение отзыва.

Улучшение отзыва Apple

Вот как это работает:

  • записи журналов прозрачности сертификатов собираются Apple
  • с помощью этой информации Apple собирает информацию об отзыве из ЦС
  • затем эта обобщенная информация автоматически становится доступной для всех клиентов Apple на регулярной основе
  • основываясь на этой информации, когда приложение iOS пытается подключиться к серверу с отозванным сертификатом, оно выполняет дополнительную проверку через OCSP.

требование

Единственное требование к приложению для поддержки этого заключается в том, чтобы используемый сертификат сервера был добавлен в журнал прозрачности сертификатов. Обычно центр сертификации уже делает это, но вы должны убедиться, что сертификат домена находится в журналах активной прозрачности для открытых сертификатов, например, используя следующую ссылку: https://transparencyreport.google.com/https/certificates

WWDC 2017, сессия 701

Существует отличная сессия WWDC, в которой эта тема и мотивы Apple подробно объясняются: WWDC 2017, сессия 701: https://developer.apple.com/videos/play/wwdc2017/701/

Около минуты 12:10 инженер Apple подробно объясняет всю тему отзыва. Около 15:30 она объясняет, что обычный OCSP потребует использования дополнительных API.

Тест сшивания OCSP на iOS

Для теста нам нужен сервер, который поддерживает сшивание OCSP и использует отозванный сертификат: https://revoked.grc.com (этот сервер найден в ответе сервера об ошибке: https://serverfault.com/a/645066 )

Затем мы можем попытаться подключиться из iOS с помощью небольшой тестовой программы, которая пытается загрузить ответ HTML и вывести его на консоль.

На основании информации из сеанса WWDC, упомянутой выше, попытка подключения должна завершиться неудачей.

...
let session = URLSession(configuration: .default)
...

func onDownloadAction() {
    let url = URL(string: "https://revoked.grc.com")!
    self.download(from: url) { (result, error) in
        if let result = result {
            print("result: " + result)
        } else {
            print("download failed")
            if let error = error {
                print("error: \(error)")
            }
        }
    }
}


func download(from url: URL, completion: @escaping(String?, Error?)->Void) {
    let dataTask = self.session.dataTask(with: url) { data, response, error in
        guard let data = data else {
            if let error = error {
                completion(nil, error)
                return
            }
            completion(nil, NSError(domain: "DownloadFailure", code: 0, userInfo:nil))
            return
        }

        guard let response = response as? HTTPURLResponse else {
            completion(nil, NSError(domain: "ResponseFailure", code: 0, userInfo:nil))
            return
        }
        print("http status: \(response.statusCode)")
        let res = String(bytes: data, encoding: .utf8)
        completion(res, nil)
    }
    dataTask.resume()
}

Если мы выполним вышеупомянутую подпрограмму в симуляторе iOS, мы сможем использовать Wireshark, чтобы проверить, прикреплен ли ответ OCSP с меткой времени, подписанный СА, к рукопожатию TLS.

С помощью nslookup revoked.grc.comмы получаем IP-адрес сервера и можем фильтровать в Wireshark с помощью ip.addr==4.79.142.205.

На скриншоте видно, что сертификат имеет статус revoked.

Wireshark

Итак, заглянув в консоль Xcodes, можно увидеть следующий вывод:

2019-10-12 21:32:25.734382+0200 OCSPTests[6701:156558] ATS failed system trust
2019-10-12 21:32:25.734526+0200 OCSPTests[6701:156558] Connection 1: system TLS Trust evaluation failed(-9802)
2019-10-12 21:32:25.734701+0200 OCSPTests[6701:156558] Connection 1: TLS Trust encountered error 3:-9802
2019-10-12 21:32:25.734787+0200 OCSPTests[6701:156558] Connection 1: encountered error(3:-9802)
2019-10-12 21:32:25.737672+0200 OCSPTests[6701:156558] Task <12408947-689F-4537-9642-C8F95E86CA62>.<1> HTTP load failed, 0/0 bytes (error code: -1200 [3:-9802])
download failed
error: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x6000037f8510>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=(
    "<cert(0x7fda78828200) s: revoked.grc.com i: DigiCert SHA2 Secure Server CA>",
    "<cert(0x7fda7882b200) s: DigiCert SHA2 Secure Server CA i: DigiCert Global Root CA>"
), NSUnderlyingError=0x600000be9170 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x6000037f8510>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
    "<cert(0x7fda78828200) s: revoked.grc.com i: DigiCert SHA2 Secure Server CA>",
    "<cert(0x7fda7882b200) s: DigiCert SHA2 Secure Server CA i: DigiCert Global Root CA>"
)}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://revoked.grc.com/, NSErrorFailingURLStringKey=https://revoked.grc.com/, NSErrorClientCertificateStateKey=0}

iOS прерывает попытку подключения к серверу с ошибкой TLS.

Тест revoked.badssl.com

revoked.badssl.com не поддерживает сшивание OCSP.

Если мы посмотрим на детали сертификата https://revoked.badssl.com , мы можем узнать:

Если кто-то загружает файл .crl (2,5 МБ) и выдает

openssl crl -inform DER -text -in ssca-sha2-g6.crl | grep 0371B58A86F6CE9C3ECB7BF42F9208FC

видно, что этот сертификат отзывается через CRL.

Интересно, что ни Safari, ни Chrome, ни iOS не распознают этот аннулированный статус. Только Mozilla Firefox отображает сообщение об ошибке ( сертификат партнера был отозван. Код ошибки: SEC_ERROR_REVOKED_CERTIFICATE ).

Причиной может быть то, что сертификат был обновлен всего несколько дней назад, и поэтому еще не попал во все локальные списки отзыва браузеров и операционных систем.

Стефан Шлехт
источник
Отличная информация здесь. Спасибо за вдумчивый ответ. Поскольку я продолжал исследовать эту тему, которую я видел так же, как и вы, поддержка CRL прекращается основными браузерами / ОС, и сшивание OCSP представляется новым рекомендуемым механизмом безопасности. В видео WWDC представитель Apple заявляет: «К сожалению, в настоящее время наши платформы НЕ проверяют отзыв по умолчанию». Что я обнаружил в своих экспериментах, так это то, что он не только не поддерживается по умолчанию, но и вообще не поддерживается (даже если вы принудительно включили настройки) @Stephan Schlecht
Unome