swift2 Swift 2.0和XCode 7中的服务器身份验证已中断

8aqjt8rx  于 2022-11-06  发布在  Swift
关注(0)|答案(3)|浏览(215)

我刚刚将代码更新为Swift 2.0,以便与Xcode 7配合使用。我的应用程序执行NSURLAuthenticationMethodServerTrustNSURLAuthenticationMethodClientCertificate身份验证。
问题是NSURLAuthenticationMethodServerTrust身份验证在我的模拟器上停止工作-但在我的iOS 8.3测试设备上仍然工作。除了我的旧项目,这不是Swift 2.0,也仍然工作。
错误:NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
从NSURLSession检索到错误:

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo=0x7fcf75053070 {NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x7fcf73700d00>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorCodeKey=-9802, NSUnderlyingError=0x7fcf735284b0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1200.)", NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://mywebapi/dosomething, NSErrorFailingURLStringKey=https://mywebapi/dosomething, _kCFStreamErrorDomainKey=3} [GetOneTimeTokenController.swift:76]

我仍在部署iOS 8.0。
以下是我处理身份验证质询的方式(使用自签名证书):

if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate {

        let urlCredential:NSURLCredential = NSURLCredential(
            identity: identityAndTrust.identityRef,
            certificates: identityAndTrust.certArray as [AnyObject],
            persistence: NSURLCredentialPersistence.ForSession);

        completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, urlCredential);

    } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {

        completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(trust: challenge.protectionSpace.serverTrust!));

    } else {

        challenge.sender?.continueWithoutCredentialForAuthenticationChallenge(challenge)
        Logger.sharedInstance.logMessage("Unexpected Authentication Challange", .Error);

    }
vmpqdwk3

vmpqdwk31#

那么你的模拟器很可能运行的是iOS 9。在iOS 9中,TLS 1.2是强制执行的。如果你不使用它,你的请求将失败。
请查看this post以了解更多信息。
您可以将以下代码放在Info.plist中绕过它:

<key>NSAppTransportSecurity</key>
<dict>
  <!--Include to allow all connections (DANGER)-->
  <key>NSAllowsArbitraryLoads</key>
      <true/>
</dict>

但它只是一个临时解决办法,直到您可以实现TLS1.2。

cczfrluj

cczfrluj2#

你没有绕过TLS层。请找到下面的答案,它对我使用自签名证书有效。
以下是与自签名SSL证书配合使用的代码更改

func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {

    if challenge.protectionSpace.authenticationMethod == (NSURLAuthenticationMethodServerTrust) {

    let serverTrust:SecTrustRef = challenge.protectionSpace.serverTrust!
    let certificate: SecCertificateRef = SecTrustGetCertificateAtIndex(serverTrust, 0)!
    let remoteCertificateData = CFBridgingRetain(SecCertificateCopyData(certificate))!
    let cerPath: String = NSBundle.mainBundle().pathForResource("xyz.com", ofType: "cer")!
    let localCertificateData = NSData(contentsOfFile:cerPath)!

        if (remoteCertificateData.isEqualToData(localCertificateData) == true) {
            let credential:NSURLCredential = NSURLCredential(forTrust: serverTrust)

            challenge.sender?.useCredential(credential, forAuthenticationChallenge: challenge)

            completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))

        } else {

            completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil)
        }
    }
    else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate
    {

        let path: String = NSBundle.mainBundle().pathForResource("client", ofType: "p12")!
        let PKCS12Data = NSData(contentsOfFile:path)!

        let identityAndTrust:IdentityAndTrust = self.extractIdentity(PKCS12Data);

            let urlCredential:NSURLCredential = NSURLCredential(
                identity: identityAndTrust.identityRef,
                certificates: identityAndTrust.certArray as? [AnyObject],
                persistence: NSURLCredentialPersistence.ForSession);

            completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, urlCredential);

    }
    else
    {
        completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil);
    }
}

 struct IdentityAndTrust {

    var identityRef:SecIdentityRef
    var trust:SecTrustRef
    var certArray:AnyObject
}

func extractIdentity(certData:NSData) -> IdentityAndTrust {
    var identityAndTrust:IdentityAndTrust!
    var securityError:OSStatus = errSecSuccess

    let path: String = NSBundle.mainBundle().pathForResource("client", ofType: "p12")!
    let PKCS12Data = NSData(contentsOfFile:path)!
    let key : NSString = kSecImportExportPassphrase as NSString
    let options : NSDictionary = [key : "xyz"]
    //create variable for holding security information
    //var privateKeyRef: SecKeyRef? = nil

    var items : CFArray?

     securityError = SecPKCS12Import(PKCS12Data, options, &items)

    if securityError == errSecSuccess {
        let certItems:CFArray = items as CFArray!;
        let certItemsArray:Array = certItems as Array
        let dict:AnyObject? = certItemsArray.first;
        if let certEntry:Dictionary = dict as? Dictionary<String, AnyObject> {

            // grab the identity
            let identityPointer:AnyObject? = certEntry["identity"];
            let secIdentityRef:SecIdentityRef = identityPointer as! SecIdentityRef!;
            print("\(identityPointer)  :::: \(secIdentityRef)")
            // grab the trust
            let trustPointer:AnyObject? = certEntry["trust"];
            let trustRef:SecTrustRef = trustPointer as! SecTrustRef;
            print("\(trustPointer)  :::: \(trustRef)")
            // grab the cert
            let chainPointer:AnyObject? = certEntry["chain"];
            identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray:  chainPointer!);
        }
    }
    return identityAndTrust;
}

在info.plist文件中完成的更改

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>amazonaws.com.cn</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSThirdPartyExceptionMinimumTLSVersion</key>
            <string>TLSv1.0</string>
        </dict>
        <key>amazonaws.com</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSThirdPartyExceptionMinimumTLSVersion</key>
            <string>TLSv1.0</string>
        </dict>
        <key>xyz.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSTemporaryExceptionMinimumTLSVersion</key>
            <string>TLSv1.2</string>
            <key>NSRequiresCertificateTransparency</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
</dict>
</plist>
eh57zj3b

eh57zj3b3#

我有同样的问题与iOS9和xcode 7只是补充:

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

plist文件。它正在工作,但在您可以实现TLS 1.2之前,它是一个临时的解决方案。

相关问题