NSURLSession TLS链验证不起作用

时间:2016-03-18 16:17:01

标签: cocoa nsurlsession

我在OS X应用程序上遇到网络问题。它不会被沙箱化。我正在使用NSURLSession的数据任务连接到一个服务器,该服务器的证书是根据TN2326的自签名CA创建的。我用URL https://rc2dev.rc2.io:8443/login调用它,它在我的开发盒上映射到linux vm的内部ip地址。

url适用于curl和nscurl,因此它不是服务器问题。在钥匙串中,我将我的CA标记为可信任,这就是nscurl工作的原因。

我将代码包装到一个隔离NSURLSession代码的包装类中:

public class LoginHandler: NSObject, NSURLSessionDataDelegate {
let urlConfig:NSURLSessionConfiguration
let baseUrl:NSURL
var loggedInHandler:LoginHandler?
var urlSession:NSURLSession!
var loginResponse:NSURLResponse?
var responseData:NSMutableData = NSMutableData()

public typealias LoginHandler = (data:NSData?, response:NSHTTPURLResponse?, error:NSError?) -> Void

init(config:NSURLSessionConfiguration, baseUrl:NSURL) {
    self.urlConfig = config
    self.baseUrl = baseUrl
    super.init()
}

public func login(login:String, password:String, handler:LoginHandler) {
    self.urlSession = NSURLSession(configuration: urlConfig, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
    loggedInHandler = handler
    let url = NSURL(string: "login", relativeToURL: baseUrl)

    let req = NSMutableURLRequest(URL: url!)
    req.HTTPMethod = "POST"
    req.addValue("application/json", forHTTPHeaderField:"Content-Type")
    req.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(["login":login, "password":password], options: [])

    let task = urlSession.dataTaskWithRequest(req);
    task.resume()
}

public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)
{
    log.info("challenge 1")
    guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
        let serverTrust = challenge.protectionSpace.serverTrust,
        let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0),
        let certPath = NSBundle.mainBundle().URLForResource("server", withExtension: "cer"),
        let storedData = NSData(contentsOfURL: certPath) where
        storedData.isEqualToData(SecCertificateCopyData(serverCert))  else
    {
        completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil)
        return
    }
    completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, nil)
}

public func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)
{
    log.info("challenge 2")
    completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, nil)
}

public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void)
{
    self.loginResponse = response
    completionHandler(NSURLSessionResponseDisposition.Allow)
}

public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)
{
    responseData.appendData(data)
}

public func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)
{
    if error != nil {
        loggedInHandler!(data: nil, response:loginResponse as! NSHTTPURLResponse!, error: error)
    } else {
        loggedInHandler!(data:responseData, response:loginResponse as! NSHTTPURLResponse!, error:nil)
    }
    urlSession.invalidateAndCancel()
}

调用的唯一委托方法是didCompleteWithError。传递给它的错误对象是

  

打印错误说明:   ▿可选(错误域= NSURLErrorDomain代码= -1004“无法连接到服务器。”UserInfo = {NSUnderlyingError = 0x61000005b270 {错误域= kCFErrorDomainCFNetwork代码= -1004“(null)”UserInfo = {_ kCFStreamErrorCodeKey = 61,_kCFStreamErrorDomainKey = 1 },NSErrorFailingURLStringKey = http://192.168.212.128:8088/login,NSErrorFailingURLKey = http://192.168.212.128:8088/login,_ kCFStreamErrorDomainKey = 1,_kCFStreamErrorCodeKey = 61,NSLocalizedDescription =无法连接到服务器。})

以下是命令行中发生的情况。需要自定义身份验证头,因此响应应为401。

mlilback@Morticia$curl -vi https://rc2dev.rc2.io:8443/login
*   Trying 192.168.212.128...
* Connected to rc2dev.rc2.io (192.168.212.128) port 8443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: Rc2Stat
> GET /login HTTP/1.1
> Host: rc2dev.rc2.io:8443
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 401 Unauthorized
HTTP/1.1 401 Unauthorized
< Date: Fri, 18 Mar 2016 10:06:53 GMT
Date: Fri, 18 Mar 2016 10:06:53 GMT
< Content-Length: 13
Content-Length: 13

< 
unauthorized
* Connection #0 to host rc2dev.rc2.io left intact
mlilback@Morticia$nscurl --verbose https://rc2dev.rc2.io:8443/login
unauthorized

启用CFNetworkDiagnostics除了从调试器获得的相同错误外,不会返回任何有用的内容。

至于ATS,我的info.plist包括:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

我完全不知道问题是什么。有什么想法吗?

0 个答案:

没有答案