0

我在 Swift 2.0 上使用 Alamofire 并为我的本地服务器实现了 ServerTrustPolicy,如您在此处看到的:

let defaultManager: Alamofire.Manager = {
    let serverTrustPolicies: [String: ServerTrustPolicy] = [
//        "localhost": .PinCertificates(
//            certificates: ServerTrustPolicy.certificatesInBundle(),
//            validateCertificateChain: false,
//            validateHost: false
//        )
        "localhost": .DisableEvaluation
    ]

    let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders

    return Alamofire.Manager(
        configuration: configuration,
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )
}()

问题是当我提出请求时,无论我使用 .PinCertificates 还是 .DisableEvaluation,我总是会收到相同的错误:

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."
UserInfo={
  NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x60c00004d980>,
  NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?,
  _kCFStreamErrorDomainKey=3, 
  _kCFStreamErrorCodeKey=-9802, 
  NSErrorPeerCertificateChainKey=<CFArray 0x6060001498a0 [0x10bb3c7b0]>{
    type = immutable, count = 1, values = (
     0 : <cert(0x61600006ed80) s: localhost i: localhost>
    )}, 
   NSUnderlyingError=0x6040000ad750 {
     Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)"
     UserInfo={
       _kCFStreamPropertySSLClientCertificateState=0, 
       kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x60c00004d980>,
       _kCFNetworkCFStreamSSLErrorOriginalValue=-9802,
       _kCFStreamErrorDomainKey=3,
       _kCFStreamErrorCodeKey=-9802,
       kCFStreamPropertySSLPeerCertificates=<CFArray 0x6060001498a0 [0x10bb3c7b0]>{
         type = immutable, count = 1, values = (
           0 : <cert(0x61600006ed80) s: localhost i: localhost>
         )}
     }
   },
   NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made.,
   NSErrorFailingURLKey=https://localhost:3000/auth/requestToken?auth_appId=d018ccd505db2cb1d5aacabb03fc2f3a,
   NSErrorFailingURLStringKey=https://localhost:3000/auth/requestToken?auth_appId=d018ccd505db2cb1d5aacabb03fc2f3a,
   NSErrorClientCertificateStateKey=0
}

我尝试使用

curl --cacert ./ca.pem https://localhost:3000

抛出的效果很好

我使用这样生成的自签名证书:

  1. 创建根 CA 私钥

    openssl genrsa -out ca.key.pem 2048
    
  2. 自签名我的根 CA

    openssl req -x509 -new -nodes -key ca.key.pem -days 1024 -out ca.crt.pem
    
  3. 通过生成密钥创建服务器证书,然后是 csr,然后使用 CA 对其进行签名

    openssl genrsa -out server.key.pem 2048
    openssl req -new -key server.key.pem -out server.csr.pem
    openssl x509 -req -in server.csr.pem -CA ca.crt.pem -CAkey ca.key.pem -CAcreateserial -out server.crt.pem -days 500
    

我使用 nodejs 的 https 模块作为我的网络服务器,我的配置如下:

require('ssl-root-cas')
  .inject()
  .addFile('./ca.crt.pem');

var privateKey = fs.readFileSync('./server.key.pem');
var certificate = fs.readFileSync('./server.crt.pem');
var credentials = { key: privateKey, cert: certificate };

var server = https.createServer(credentials, app);
server.listen(port);

我查看了 Alamofire 源代码,发现在委托方法中:

public func URLSession(
        session: NSURLSession,
        didReceiveChallenge challenge: NSURLAuthenticationChallenge,
        completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void))
{
    var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
    var credential: NSURLCredential?

    if let sessionDidReceiveChallenge = sessionDidReceiveChallenge {
        (disposition, credential) = sessionDidReceiveChallenge(session, challenge)
    } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
        let host = challenge.protectionSpace.host

        if let
            serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
            serverTrust = challenge.protectionSpace.serverTrust
        {
            if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
                disposition = .UseCredential
                credential = NSURLCredential(forTrust: serverTrust)
            } else {
                disposition = .CancelAuthenticationChallenge
            }
        }
    }

    completionHandler(disposition, credential)
}

调用serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host)实际返回 true。这意味着错误可能发生在 completionHandler 代码中的某个地方,对吧?

我在处理证书方面做错了什么吗?

PS:defaultManager没有被释放:)

4

1 回答 1

0

首先,确保您defaultManager没有被释放。如果是,您将始终得到 -999。话虽如此,如果您使用,.DisableEvaluation那么我会假设您的 SSL 配置服务器端存在一些更大的问题。

你能成功地卷曲你的网络服务吗?

当您提供更多信息时,我会相应地更新我的答案。

于 2015-08-31T04:54:09.197 回答