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.com
otrzymujemy 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
.
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.