Appleプラットフォームでは、クライアントはCAの証明書失効リスト(CRL)をチェックせず、デフォルトでOCSPを使用しません。
ただし、AppleプラットフォームはOCSPステープリングをサポートしており、代わりに、失効拡張を呼び出すメカニズムを提供します。これにより、実際にOCSP呼び出しが発生する可能性があります。詳細は以下を参照してください。
OCSPステープリング
最初にOCSPステープリングの説明:
オンライン証明書状態プロトコル(OCSP)ステープル正式として知られ、TLS証明書ステータス要求拡張は、X.509デジタル証明書の失効状態をチェックするための規格です。1証明書のプレゼンターは、CAによって署名されたタイムスタンプ付きのOCSP応答を最初のTLSハンドシェイクに追加(「ステープル」)することにより、オンライン証明書ステータスプロトコル(OCSP)応答の提供に関連するリソースコストを負担できるため、必要がなくなります。セキュリティとパフォーマンスの両方を向上させることを目的として、クライアントがCAに連絡するため。
https://en.wikipedia.org/wiki/OCSP_staplingを参照してください
OCSPとOCSPステイプルの違い
クライアントが従来のOCSPフローでサーバーに接続し、証明書を取得する場合、クライアントは、受信した証明書がCAに要求することによって取り消されているかどうかを確認します。これにはいくつかの欠点があります。たとえば、追加のネットワーク接続が必要であり、情報が暗号化されていないため、データのプライバシーの問題が発生します。
OCSPステープリングを通じて、サーバーはCAに署名された失効情報を要求し、それをTLSハンドシェイクに追加します。
これは、OCSPステープリングを使用している場合、iOSからCAサーバーへのOCSP要求が表示されないことも意味します。
OCSPステープリングの欠点
接続するサーバーは、OCSPステープリングをサポートしている必要があります。これは、悪意のあるサーバーからの保護も行いません。
それがAppleが失効強化を提供する主な理由です。
Appleの失効の強化
仕組みは次のとおりです。
- 証明書の透明性ログのエントリはAppleによって収集されます
- この情報を使用して、AppleはCAから失効に関する情報を収集します
- この集約された情報は、すべてのAppleクライアントが定期的に自動的に利用できるようになります
- この情報に基づいて、iOSアプリが失効した証明書でサーバーに接続しようとすると、OCSPを介して追加のチェックが実行されます。
要件
アプリがこれをサポートするための唯一の要件は、使用されるサーバー証明書が証明書透過性ログに追加されることです。通常、CAは既にそれを行っていますが、ドメイン証明書がパブリック証明書のアクティブな透過性ログにあることを確認する必要があります。たとえば、次のリンクを使用します:https : //transparencyreport.google.com/https/certificates
WWDC 2017、セッション701
このトピックとAppleの動機が詳細に説明されている優れたWWDCセッションがあります:WWDC 2017、セッション701:https : //developer.apple.com/videos/play/wwdc2017/701/
約12:10頃に、アップルのエンジニアが失効トピック全体を詳細に説明します。15:30頃、彼女は通常のOCSPでは追加のAPIを使用する必要があると説明しました。
iOSでのOCSPステープリングのテスト
テストには、OCSPステープリングをサポートし、失効した証明書を使用するサーバーが必要です:https : //revoked.grc.com
(このサーバー障害の回答でこのサーバーを見つけてください:https : //serverfault.com/a/645066)
次に、HTML応答をダウンロードしてコンソールに出力しようとする小さなテストプログラムを使用して、iOSから接続を試みます。
上記の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を使用して、CAによって署名されたタイムスタンプ付きの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.5MB)をダウンロードして、
openssl crl -inform DER -text -in ssca-sha2-g6.crl | grep 0371B58A86F6CE9C3ECB7BF42F9208FC
この証明書がCRL経由で取り消されていることがわかります。
興味深いことに、SafariもChromeもiOSもこの取り消されたステータスを認識しません。Mozilla Firefoxのみがエラーメッセージを表示します(ピアの証明書が取り消されました。エラーコード:SEC_ERROR_REVOKED_CERTIFICATE)。
その理由は、証明書がほんの数日前に更新されたため、ブラウザーとオペレーティングシステムのローカルの取り消しリストすべてにまだ届いていないためです。