简体   繁体   English

在iOS上使用CFStream套接字接受不受信任的SSL服务器证书

[英]Accept untrusted SSL server certificate with CFStream socket on iOS

I need to open a CFStream socket connection to a server that has an untrusted CA root. 我需要打开与具有不受信任的CA根服务器的服务器的CFStream套接字连接。 I have the certificate of the server, and I can create a SecCertificateRef structure from it. 我有服务器的证书,可以从中创建一个SecCertificateRef结构。 The problem is how to set up the properties of the stream. 问题是如何设置流的属性。

I think I should set the kCFStreamPropertySSLSettings property to a CFDictionary that in turn contains a kCFStreamSSLCertificates key. 我认为我应该将kCFStreamPropertySSLSettings属性设置为CFDictionary ,而CFDictionary又包含一个kCFStreamSSLCertificates密钥。 This key should hold a "a CFArray of SecCertificateRefs except for the first element in the array, which is a SecIdentityRef" according to the docs. 根据文档,此键应包含一个“ SecCertificateRefs CFArray,但数组中的第一个元素为SecIdentityRef”。 Now I can create the SecCertificateRef from the server's certificate that I'll ship with the app, but how to get the SecIdentityRef ? 现在,我可以从应用SecCertificateRef的服务器证书中创建SecCertificateRef ,但是如何获取SecIdentityRef I guess it should be the client identity but I absolutely don't want client side authentication for now. 我想应该是客户端身份,但是我现在绝对不希望客户端身份验证 And I can't find a way how to feed CFStream only with the server certificate. 而且我找不到仅使用服务器证书来提供CFStream的方法。

Note, I don't want to add the untrusted certificate to the keychain, neither disable kCFStreamSSLValidatesCertificateChain in the settings. 请注意,我不想将不受信任的证书添加到钥匙串中,也不要在设置中禁用kCFStreamSSLValidatesCertificateChain。 I need to accept the server authentication only if it is based on my own server certificate data loaded from the disk, and only on this CFStream. 仅当它基于从磁盘加载的我自己的服务器证书数据并且仅基于此CFStream时,我才需要接受服务器身份验证。

Basically you have to: 基本上,您必须:

  1. disable default trust evaluation using kCFStreamSSLValidatesCertificateChain 使用kCFStreamSSLValidatesCertificateChain禁用默认信任评估
  2. get the trust object ( kCFStreamPropertySSLPeerTrust ) once connected to the stream (but before sending any data, ie, on kCFStreamEventCanAcceptBytes or kCFStreamEventHasBytesAvailable events) 一旦连接到流(但在发送任何数据之前,即在kCFStreamEventCanAcceptByteskCFStreamEventHasBytesAvailable事件上),就获得信任对象( kCFStreamPropertySSLPeerTrust
  3. set your self-signed root certicate as a trusted anchor for that trust object 将您的自签名根证书设置为该信任对象的信任锚
  4. optionally, you may add custom SSL policies to the trust object (eg, hostname doesn't match certificate CN), but if you do that it's important that you do it before setting the trusted anchor or you may get kSecTrustResultRecoverableTrustFailure result (可选)您可以向信任对象添加自定义SSL策略(例如,主机名与证书CN不匹配),但是如果这样做,那么在设置受信任锚之前必须先执行此操作,否则可能会获得kSecTrustResultRecoverableTrustFailure结果
  5. evaluate the trust object ( SecTrustEvaluate ) and check result is either kSecTrustResultProceed or kSecTrustResultUnspecified 评估信任对象( SecTrustEvaluate )并检查结果是kSecTrustResultProceed还是kSecTrustResultUnspecified

I do not have the direct answer to your question, but perhaps few guidelines: 对于您的问题,我没有直接的答案,但是可能没有几个指导原则:

  1. Why do you need to use the CFStream API and not the more intuitive NSURLConnection ? 为什么需要使用CFStream API而不是更直观的NSURLConnection
    From what I could find in the documentation, it seams like not everything that is available for Mac OS X, regarding CFStream API, is available for iOS. 从我在文档中可以找到的地方来看,它似乎并不是Mac OS X上与CFStream API有关的所有内容都适用于iOS。 So think about it, and see if you can switch to NSURLConnection :-) 因此,请考虑一下,看看是否可以切换到NSURLConnection :-)

  2. For NSURLConnection, you can use the NSURLConnectionDelegate methods to get the SSL challenge and validate the certificate on your own. 对于NSURLConnection,可以使用NSURLConnectionDelegate方法来获取SSL质询并自行验证证书。 You can check the wsdl2objc project, where I have implemented these features: 您可以检查wsdl2objc项目,在该项目中我实现了以下功能:

  3. Now about your questions :-) 现在关于您的问题:-)
    I don't see how you can set a custom (untrusted) CA in kCFStreamPropertySSLSettings . 我看不到如何在kCFStreamPropertySSLSettings中设置自定义(不受信任的)CA。 I'm not sure if it can be done by using kCFStreamSSLCertificates since it is meant to be used for setting client-side certificates (thus the requirement of having the SecIdentityRef on index 0, which basically provides the private key). 我不确定是否可以使用kCFStreamSSLCertificates来完成此操作,因为它旨在用于设置客户端证书(因此要求在索引0上具有SecIdentityRef ,该索引基本上提供了私钥)。

  4. When you say you don't want to add the certificate to the keychain, do you mean manually or programmatically ? 当您说不想将证书添加到钥匙串时,是指手动还是以编程方式进行? I guess you don't like the users of your app to have to do it manually, but you can use the Security API to import the certificate programatically. 我想您不希望应用程序的用户必须手动执行此操作,但是您可以使用Security API以编程方式导入证书。 In this case your certificate will be imported in a sandboxed keychain which is only available for your application. 在这种情况下,您的证书将被导入到仅适用于您的应用程序的沙盒钥匙串中。 (again, not sure if this will work but worths the try) (再次,不确定是否可以,但是值得尝试)

In my applications I use NSURLConnectionDelegate to manually validate untrusted certificates. 在我的应用程序中,我使用NSURLConnectionDelegate手动验证不受信任的证书。

Regards, 问候,
Pece 佩斯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM