如何使CRL和OSCP检查在iOS上运行?


9

我无法在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标志,则两者均成功。我已经尝试过仅使用OSCP或仅使用CRL的所有不同排列方式,但没有一种能达到我期望的效果。

Apple 的州文件SecPolicyCreateRevocation

除非您希望覆盖默认的系统行为,例如强制执行特定方法或完全禁用吊销检查,否则通常无需自己创建吊销策略。

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

我将CharlesProxy附加到我的设备上,并在侦听所有网络流量的同时多次运行该代码,并且没有出站请求发送到CRL,这解释了为什么RequirePositiveResponse选中该标志时所有请求都失败。

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

Apple安全性库不支持CRL检查吗?如果是的话,是否有人知道配置以使其正确响应?我使用什么替代方法来进行CRL验证,我假设在金融区或其他敏感地区进行交易的高安全性移动应用程序将无法覆盖这一覆盖范围。

更新 为了进行比较,我certutil -f -urlfetch -verify MYCERT.cer使用certutil运行,并将 Fiddler附加到运行命令的框。我收到了iOS无法提供的预期结果,并且看到了通过提琴手通过HTTP向CRL发出的出站请求。

我创建了一个赏金计划,以引起更多对此的兴趣。我希望有人对上面做错了什么或为什么在iOS上不起作用有更多详细信息。

Answers:


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可以从CA收集有关吊销的信息
  • 然后,这些汇总信息会自动自动定期提供给所有Apple客户
  • 根据此信息,当iOS应用尝试使用吊销的证书连接到服务器时,它将通过OCSP执行附加检查。

需求

应用程序要支持此功能的唯一要求是,将使用的服务器证书添加到证书透明性日志中。通常,CA已经这样做了,但是您应该检查域证书是否在公共证书的活动透明日志中,例如,使用以下链接:https : //transparencyreport.google.com/https/certificates

WWDC 2017,会议701

有一个很棒的WWDC会议,其中详细介绍了此主题和Apple的动机:WWDC 2017,会议701:https : //developer.apple.com/videos/play/wwdc2017/701/

苹果工程师在12:10左右详细解释了整个撤销主题。她在15:30左右解释说,正常的OCSP将需要使用其他API。

在iOS上测试OCSP装订

为了进行测试,我们需要一台支持OCSP装订并使用吊销证书的 服务器:https : //revoked.grc.com(在此serverfault答案中找到此服务器: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 Simulator中执行上述例程,则可以使用Wireshark来检查是否将CA签名的带时间戳的OCSP响应装订到TLS握手中。

随着nslookup revoked.grc.com我们获得了服务器的IP地址,并可以在Wireshark的带过滤器ip.addr==4.79.142.205

在屏幕截图中,您可以看到证书的状态为revoked

Wireshark

因此,看看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错误连接到服务器的尝试。

测试已撤销.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)。

原因可能是该证书仅在几天前进行了更新,因此尚未在所有本地浏览器和操作系统的吊销列表中找到它。


很好的信息在这里。感谢您的深思熟虑的回答。当我继续研究该主题时,我和您看到的一样,主要的浏览器/ OS都放弃了CRL支持,而OCSP装订似乎是推荐的新安全机制。苹果公司代表在WWDC视频中说:“很遗憾,我们的平台当前不检查默认情况下的撤销”。我通过实验发现,不仅默认情况下不支持此功能,而且也不支持(即使您强行启用了设置)@Stephan Schlecht
Unome,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.