Jak uzyskać sprawdzanie listy CRL i OSCP w systemie iOS?

9

Nie mogę uzyskać list CRL działających na iOS. Stworzyłem dwa przypadki testowe. Mam ważny certyfikat wydany przez urząd certyfikacji. Mam inny ważny certyfikat, wydany przez urząd certyfikacji, ale urząd certyfikacji dodał ten certyfikat do swojej listy CRL.

Następnie konfiguruję zasadę odwołania, która umożliwia sprawdzanie listy CRL i wymaga powodzenia.

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
}

Oczekuję, że certyfikat znajdujący się na liście CRL będzie niezaufany, a certyfikat czysty będzie zaufany.

Biorąc pod uwagę powyższą konfigurację, oba zawodzą jako niezaufane. Jeśli usunę kSecRevocationRequirePositiveResponseflagę, oba się powiedzą. Próbowałem różnych kombinacji używania tylko OSCP lub tylko CRL i nic nie działa tak, jakbym się spodziewał.

Dokumentacja jabłek dla SecPolicyCreateRevocationstanów:

Zwykle nie trzeba samodzielnie tworzyć zasad odwołania, chyba że chcesz zastąpić domyślne zachowanie systemu, na przykład wymusić określoną metodę lub całkowicie wyłączyć sprawdzanie odwołania.

Używanie tylko SecPolicyCreateBasicX509zasad pozwala obu osiągnąć sukces (gdy drugi certyfikat powinien zawieść), więc czy domyślne zachowanie Apple w ogóle nie sprawdza listy CRL?

I załączeniu CharlesProxy do mojego urządzenia i pobiegł kod kilka razy podczas słuchania całego ruchu sieciowego, a żadnych żądań wychodzących kiedykolwiek pójść do CRL co tłumaczy, dlaczego wszyscy nie kiedy RequirePositiveResponsejest zaznaczona flaga.

Próbowałem również nawigować bezpośrednio z urządzenia do listy CRL za pomocą a URLRequesti udało mi się uzyskać dane listy CRL na urządzeniu bez żadnych problemów.

Czy sprawdzanie listy CRL nie jest obsługiwane przez bibliotekę Apple Security? Jeśli tak, to czy ktoś wymyślił konfigurację, aby poprawnie zareagować? Jakie alternatywy są używane do sprawdzania poprawności listy CRL, zakładam, że aplikacje mobilne o wysokim poziomie bezpieczeństwa działające w dzielnicy finansowej lub w innych wrażliwych obszarach nie pozwoliłyby na taką lukę w zasięgu.

AKTUALIZACJA Dla porównania uruchomiłemcertutil -f -urlfetch -verify MYCERT.cerprzy użyciu certutil i podłączyłem Fiddler do skrzynki z uruchomionym poleceniem. Otrzymuję oczekiwane wyniki, których nie daje mi iOS, i widzę żądanie wychodzące do listy CRL za pośrednictwem HTTP przez skrzypek.

Stworzyłem nagrodę, aby zwiększyć zainteresowanie tym tematem. Mam nadzieję, że ktoś ma więcej szczegółów na temat tego, co zostało źle zrobione powyżej lub dlaczego to nie działa na iOS.

Unome
źródło

Odpowiedzi:

7

Na platformach Apple klienci nie sprawdzają listy odwołań certyfikatów (CRL) urzędów certyfikacji ani domyślnie nie używają protokołu OCSP.

Platformy Apple obsługują jednak zszywanie OCSP i alternatywnie zapewniają mechanizm, który nazywają Ulepszaniem odwołania, co może rzeczywiście prowadzić do połączenia OCSP, patrz szczegóły poniżej.

Zszywanie OCSP

Najpierw wyjaśnienie zszywania OCSP:

Online Certificate Status Protocol (OCSP) zszywanie , formalnie znany jako Stan żądania certyfikatów TLS rozszerzenia, to standard do sprawdzania stanu odwołania certyfikatów X.509 cyfrowych. 1 Pozwala to prezenterowi certyfikatu ponieść koszty zasobów związane z udzieleniem odpowiedzi protokołu OCSP (Online Certificate Status Protocol) poprzez dołączenie („zszywanie”) odpowiedzi OCSP ze znacznikiem czasu podpisanej przez urząd certyfikacji do początkowego uzgadniania TLS, eliminując potrzebę aby klienci mogli skontaktować się z urzędem certyfikacji w celu poprawy zarówno bezpieczeństwa, jak i wydajności.

patrz https://en.wikipedia.org/wiki/OCSP_stapling

Różnice między zszywaniem OCSP i OCSP

Jeśli klient łączy się z serwerem w tradycyjnym przepływie OCSP i pobiera certyfikat, sprawdza, czy otrzymany certyfikat został odwołany, wysyłając żądanie do urzędu certyfikacji. Ma to pewne wady, na przykład wymagane jest dodatkowe połączenie sieciowe, informacje są nieszyfrowane, a zatem stanowią problem prywatności danych.

Za pomocą zszywania OCSP serwer żąda podpisania informacji o odwołaniu od urzędu certyfikacji i dodaje je do uzgadniania TLS.

Oznacza to również, że podczas korzystania ze zszywania OCSP nie widzisz żądania OCSP z iOS do serwera CA.

Wady zszywania OCSP

Serwer, z którym się łączysz, musi obsługiwać zszywanie OCSP. Nie chroni to również przed złośliwymi serwerami.

To są główne powody, dla których Apple zapewnia ulepszenie odwołania.

Ulepszenie odwołania Apple

Oto jak to działa:

  • Wpisy do dzienników przezroczystości certyfikatów są gromadzone przez Apple
  • z tymi informacjami Apple zbiera informacje o odwołaniach z urzędów certyfikacji
  • te zagregowane informacje są następnie automatycznie udostępniane wszystkim klientom Apple na bieżąco
  • na podstawie tych informacji, gdy aplikacja iOS próbuje połączyć się z serwerem za pomocą unieważnionego certyfikatu, przeprowadza dodatkową kontrolę za pośrednictwem protokołu OCSP.

Wymaganie

Jedynym wymaganiem aplikacji do obsługi tego jest dodanie certyfikatu serwera do dziennika przezroczystości certyfikatu. Zwykle urząd certyfikacji już to robi, ale należy sprawdzić, czy certyfikat domeny znajduje się w aktywnych dziennikach przezroczystości dla certyfikatów publicznych, np. Za pomocą następującego łącza: https://transparencyreport.google.com/https/certificates

WWDC 2017, sesja 701

Istnieje doskonała sesja WWDC, w której szczegółowo wyjaśniono ten temat i motywy Apple: WWDC 2017, sesja 701: https://developer.apple.com/videos/play/wwdc2017/701/

Około minuty 12:10 inżynier Apple szczegółowo wyjaśnia cały temat odwołania. Około 15:30 wyjaśnia, że ​​normalne OCSP wymagałoby użycia dodatkowych interfejsów API.

Test zszywania OCSP na iOS

Do testu potrzebujemy serwera, który obsługuje zszywanie OCSP i korzysta z unieważnionego certyfikatu: https://revoked.grc.com (znaleziono ten serwer w odpowiedzi na błąd serwera: https://serverfault.com/a/645066 )

Następnie możemy spróbować połączyć się z iOS za pomocą małego programu testowego, który próbuje pobrać odpowiedź HTML i wysłać ją do konsoli.

Na podstawie informacji z wyżej wspomnianej sesji WWDC próba połączenia powinna zakończyć się niepowodzeniem.

...
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()
}

Jeśli wykonamy powyższą procedurę w Symulatorze iOS, możemy użyć Wireshark, aby sprawdzić, czy sygnatura czasowa OCSP podpisana przez urząd certyfikacji jest zszyta z uzgadnianiem TLS.

Z nslookup revoked.grc.comotrzymujemy adres IP serwera i można filtrować w Wireshark z ip.addr==4.79.142.205.

Na zrzucie ekranu widać, że certyfikat ma status revoked.

wireshark

Spoglądając na konsolę Xcodes, można zobaczyć następujące dane wyjściowe:

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 przerywa próbę połączenia z serwerem z błędem TLS.

Przetestuj revoked.badssl.com

revoked.badssl.com nie obsługuje zszywania OCSP.

Jeśli spojrzymy na szczegóły certyfikatu https://revoked.badssl.com , możemy dowiedzieć się:

Jeśli pobierzesz plik .crl (2,5 MB) i wydasz a

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

widać, że ten certyfikat został unieważniony przez CRL.

Co ciekawe, ani Safari, ani Chrome, ani iOS nie rozpoznają tego unieważnionego statusu. Tylko Mozilla Firefox wyświetla komunikat o błędzie ( certyfikat Peera został odwołany. Kod błędu: SEC_ERROR_REVOKED_CERTIFICATE ).

Powodem może być to, że certyfikat został odnowiony zaledwie kilka dni temu i dlatego nie znalazł się jeszcze na wszystkich lokalnych listach odwołań przeglądarek i systemów operacyjnych.

Stephan Schlecht
źródło
Świetna informacja tutaj. Dzięki za miłą odpowiedź. Ponieważ kontynuowałem badania tego tematu, widziałem to samo, co Ty, obsługa CRL jest odrzucana przez główne przeglądarki / systemy operacyjne, a zszywanie OCSP wydaje się być nowym zalecanym mechanizmem bezpieczeństwa. W filmie WWDC przedstawiciel Apple stwierdza: „Niestety obecnie nasze platformy NIE sprawdzają domyślnie odwołania”. Podczas moich eksperymentów odkryłem, że nie tylko nie jest ono domyślnie obsługiwane, ale w ogóle nie jest obsługiwane (nawet jeśli wymusisz włączenie ustawień) @Stephan Schlecht
Unome