ios - 如何让 CRL 和 OCSP 检查在 iOS 上工作?

标签 ios swift security certificate certificate-revocation

我无法在 iOS 上使用 CRL。我创建了两个测试用例。我有一个由 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 flag,双方都成功了。我已经尝试了仅使用 OSCP 或仅使用 CRL 的所有不同排列,但没有任何效果符合我的预期。

苹果 documentationSecPolicyCreateRevocation状态:

It's usually not necessary to create a revocation policy yourself unless you wish to override default system behavior, for example to force a particular method, or to disable revocation checking entirely.



仅使用 SecPolicyCreateBasicX509策略允许两者都成功(当第二个证书失败时),那么 Apple 的默认行为是根本不进行 CRL 检查吗?

我附上 CharlesProxy到我的设备,并在监听所有网络流量的同时多次运行代码,并且没有出站请求进入 CRL 这解释了为什么在 RequirePositiveResponse 时所有失败标志被检查。

我还尝试使用 URLRequest 直接从设备导航到 CRL。 ,并且能够毫无问题地获取设备上的 CRL 数据。

Apple 安全库不支持 CRL 检查吗?如果是,是否有人想出配置以使其正确响应? bing 使用哪些替代方案来进行 CRL 验证,我假设在金融区或其他敏感区域处理的高安全性移动应用程序不允许这种覆盖差距。

更新
为了比较,我跑了 certutil -f -urlfetch -verify MYCERT.cer使用 certutil,我附上了 Fiddler到运行命令的框。我收到了 iOS 没有给我的预期结果,并且我看到了一个通过 fiddler 通过 HTTP 向 CRL 发出的出站请求。

我创建了一个赏金来引起更多的兴趣。我希望有人能更详细地了解上面做错了什么,或者为什么这在 iOS 上不起作用。

最佳答案

在 Apple 平台上,客户端既不检查 CA 的证书吊销列表 (CRL),也不默认使用 OCSP。

然而,Apple 平台支持 OCSP 装订,并且它们提供了一种称为撤销增强的替代机制,这确实可能导致 OCSP 调用,如下所示。

OCSP 装订

首先解释一下OCSP装订:

Online Certificate Status Protocol (OCSP) stapling, formally known as the TLS Certificate Status Request extension, is a standard for checking the revocation status of X.509 digital certificates.1 It allows the presenter of a certificate to bear the resource cost involved in providing Online Certificate Status Protocol (OCSP) responses by appending ("stapling") a time-stamped OCSP response signed by the CA to the initial TLS handshake, eliminating the need for clients to contact the CA, with the aim of improving both security and performance.



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

OCSP 和 OCSP 装订的区别

如果客户端在传统 OCSP 流中连接到服务器并检索证书,它会通过向 CA 发出请求来检查收到的证书是否已被吊销。这有一些缺点:例如,需要额外的网络连接,信息未加密,因此存在数据隐私问题。

通过 OCSP stapling,服务器向 CA 请求签名撤销信息并将其添加到 TLS 握手中。

这也意味着在使用 OCSP 装订时,您看不到从 iOS 到 CA 服务器的 OCSP 请求。

OCSP 装订的缺点

您要连接的服务器必须支持 OCSP 装订。这也不能防止恶意服务器。

这些是 Apple 提供吊销增强功能的主要原因。

Apple 的撤销增强

这是它的工作原理:
  • 证书透明度日志条目由 Apple 收集
  • 有了这些信息,Apple 就会从 CA 收集有关撤销的信息
  • 然后,这些汇总信息会定期自动提供给所有 Apple 客户
  • 基于此信息,当 iOS 应用程序尝试连接到带有吊销证书的服务器时,它会通过 OCSP 执行额外检查。

  • 需求

    应用程序支持此功能的唯一要求是将使用的服务器证书添加到证书透明度日志中。公共(public)证书颁发机构可能已经这样做了,但您应该检查域证书是否在公共(public)证书的事件透明度日志中,例如使用以下链接:https://transparencyreport.google.com/https/certificates

    WWDC 2017, session 701

    有一个很好的 WWDC session ,其中详细解释了这个主题和 Apple 的动机:WWDC 2017, session 701:https://developer.apple.com/videos/play/wwdc2017/701/

    大约 12:10 分钟,一位 Apple 工程师详细解释了整个撤销主题。在 15:30 左右,她解释说正常的 OCSP 需要使用额外的 API。

    iOS上OCSP Stapling的测试

    为了进行测试,我们需要一个支持 OCSP 装订并使用吊销证书的服务器:例如https://revoked.grc.com
    (在此服务器错误答案中找到此服务器:https://serverfault.com/a/645066)

    然后我们可以尝试从 iOS 连接一个小的测试程序,该程序尝试下载 HTML 响应并将其输出到控制台。

    根据上面提到的 WWDC session 的信息,连接尝试应该会失败:
    ...
    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 .

    wireshark

    因此,查看 Xcode 控制台,可以看到以下输出:
    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 错误中止连接到服务器的尝试。

    测试已撤销.badssl.com

    revoked.badssl.com 不支持 OCSP 装订。

    如果我们看一下https://revoked.badssl.com的证书详情,我们发现:
  • 它有序列号:0371B58A86F6CE9C3ECB7BF42F9208FC
  • CRL URL 是:http://crl3.digicert.com/ssca-sha2-g6.crl

  • 如果下载 .crl 文件 (2.5MB) 并运行
    openssl crl -inform DER -text -in ssca-sha2-g6.crl | grep 0371B58A86F6CE9C3ECB7BF42F9208FC
    

    可以看出,该证书确实是通过 CRL 吊销的。

    有趣的是,Safari、Chrome 和 iOS 都无法识别这种撤销状态。只有 Mozilla Firefox 会显示错误消息(Peer 的证书已被撤销。错误代码:SEC_ERROR_REVOKED_CERTIFICATE)。

    原因可能是证书仅在几天前更新,因此尚未进入所有浏览器和操作系统的本地撤销列表。

    关于ios - 如何让 CRL 和 OCSP 检查在 iOS 上工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58227552/

    相关文章:

    encryption - 如何将私有(private)加密用户数据存储在数据库中,但使其可供其他选定用户使用?

    ios - iOS 应用程序通过 https 将用户名和密码发送到服务器的安全问题

    java - 防止 Java 代理在运行时附加

    ios - 解析 Facebook 登录应用程序必须请求基本读取权限

    iphone - iOS 检测连接速度或类型

    android - 在Titanium中将大JSON存储在iOS和Android中

    ios - 在 iOS 9.0 中以编程方式显示表情符号键盘

    ios - 即使将planeDetection设置为空,ARKitplaneDetection仍会继续

    ios - 如何过滤数组中的很多项

    swift - 全局 Realm 对象 : Singleton or Fetch It Every Time?