Как заставить CRL и OSCP Checking работать на iOS? - PullRequest
7 голосов
/ 04 октября 2019

Я не могу заставить 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, и ничего не работает так, как я ожидал.

Apple документация для SecPolicyCreateRevocation состояний:

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

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

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

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

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

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

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

1 Ответ

3 голосов
/ 12 октября 2019

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

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

Сшивание OCSP

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

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

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

Различия между OCSP и OCSP Сшивание

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

При сшивании OCSP сервер запрашивает у CA подписанную информацию об отзыве и добавляет еена рукопожатие 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 Simulator, мы можем использовать Wireshark, чтобы проверить, является ли ответ OCSP с меткой времени, подписанныйCA скреплен с рукопожатием 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 ).

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

...