На платформах 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
.
Итак, заглянув в консоль 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 ).
Причиной может быть то, что сертификат был обновлен всего несколько дней назад, и поэтому еще не попал во все локальные списки отзыва браузеров и операционных систем.