CRLおよびOSCPチェックをiOSで機能させるにはどうすればよいですか?


9

iOSでCRLを機能させることができません。2つのテストケースを作成しました。CAが発行した有効な証明書を持っています。CAによって発行された有効な別の証明書がありますが、CAはその証明書を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のみを使用するさまざまな順列をすべて試しましたが、期待どおりに機能しません。

リンゴのドキュメントのためのSecPolicyCreateRevocation状態:

特定のメソッドを強制したり、失効チェックを完全に無効にしたりするなど、デフォルトのシステム動作を上書きしたくない場合を除いて、通常、失効ポリシーを自分で作成する必要はありません。

のみを使用して SecPolicyCreateBasicX509ポリシー両方が成功します(2番目の証明書が失敗した場合)ので、Appleのデフォルトの動作では、CRLチェックをまったく行わないのですか?

CharlesProxyを添付しました私のデバイスに、そしてすべてのネットワークトラフィックを聞きながら、コードを複数回実行し、何のアウトバウンド要求は、これまでときにすべて失敗した理由を説明CRLに行くんRequirePositiveResponseフラグがチェックされています。

また、デバイスを使用してCRLに直接移動してみました URLRequestましたが、問題なくデバイスでCRLデータを取得できました。

Apple SecurityライブラリではCRLチェックはサポートされていませんか?もしそうなら、誰かがそれを正しく応答させるための設定を理解しましたか?CRL検証を実行するためにどのような代替手段が使用されているか、金融街やその他の機密性の高い領域で処理される高セキュリティモバイルアプリケーションではこのカバレッジギャップが許容されないと想定しています。

UPDATE 比較のために、certutil -f -urlfetch -verify MYCERT.cercertutilを使用して実行し、 Fiddlerをアタッチしましたして実行し、コマンドを実行するボックスにしました。iOSが提供していないと予想される結果を受け取り、fiddlerを介してHTTP経由でCRLへの送信要求を確認します。

私はこれにさらに興味を引くための賞金を作りました。上記の何が間違っているのか、なぜこれがiOSで機能しないのかについて誰かが詳細を知っていることを願っています。

回答:


7

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)。

その理由は、証明書がほんの数日前に更新されたため、ブラウザーとオペレーティングシステムのローカルの取り消しリストすべてにまだ届いていないためです。


ここにすばらしい情報があります。思慮深い答えをありがとう。私はあなたと同じようにこのトピックを調査し続けてきたので、CRLサポートは主要なブラウザー/ OSによって削除されており、OCSPステープリングは新しい推奨されるセキュリティメカニズムのようです。WWDCビデオでは、Appleの担当者は次のように述べています。私の実験でわかったことは、デフォルトでサポートされていないだけでなく、まったくサポートされていないことです(設定をオンにしても)@Stephan Schlecht
Unome
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.