2015-06-18 7 views
5

Ich habe gerade meinen Code zu Swift 2.0 aktualisiert, um mit Xcode 7 zu arbeiten. Meine App führt NSURLAuthenticationMethodServerTrust und NSURLAuthenticationMethodClientCertificate Authentifizierung.Server-Authentifizierung in Swift 2.0 & XCode 7 gebrochen

Das Problem ist NSURLAuthenticationMethodServerTrust Authentifizierung funktioniert nicht mehr auf meinem Simulator - funktioniert aber immer noch auf meinem Testgerät mit iOS 8.3. Neben meinem alten Projekt, das nicht Swift 2.0 ist, funktioniert auch noch.

Fehler: NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

Fehler von NSURLSession Introduction:

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] 

Ich bin Targeting noch iOS 8.0 für die Bereitstellung.

Dies ist, wie ich die Authentifizierung Herausforderung (mit einem selbstsignierten Zertifikat) behandeln:

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); 

    } 

Antwort

2

Sie haben die TLS-Ebene nicht umgehen müssen. Bitte finden Sie die Antwort unten, die für mich mit selbst signierten Zertifikat funktionierte.

Im Folgenden sind die Code-Änderungen, die mit Selbst signierten SSL-Zertifikat

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; 
} 

Änderungen erfolgten in der Datei info.plist adaequat

 <?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> 
17

Ihr Simulator höchstwahrscheinlich mit iOS 9 dann. In iOS 9 wird TLS 1.2 erzwungen. Wenn Sie es nicht verwenden, werden Ihre Anforderungen fehlschlagen.

Auschecken this post für weitere Informationen.

Sie können es umgehen, indem sie diese setzen in Ihrem Info.plist:

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

aber es ist einfach eine vorübergehende Lösung, bis Sie 1.2 TLS implementieren können.

+0

Danke. Nur ein (wahrscheinlich naheliegender Kommentar - für relative newbs wie mich) - setze dies an den unteren Rand der Datei und achte darauf, dass die letzten beiden Zeilen, und, danach noch vorhanden sind. Meine ersten Versuche, es an die Spitze zu legen, verschmutzten die XML-Formatierung (Sie erhalten eine Fehlermeldung, dass "Info.plist nicht im richtigen Format ist", wenn Sie es falsch platzieren). – user3741598

0

ich gleiches Problem mit iOS9 & Xcode 7 Nur hatte hinzufügen :

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

an die Plist-Datei. Es funktioniert, aber es ist eine temporäre Problemumgehung, bis Sie TLS 1.2 implementieren können.

+0

Die obigen Codezeilen umgehen nur die TLS-Sicherheitsebene und dies ist nicht akzeptabel, wenn Sie an der App arbeiten, bei der Client-sichere Informationen über das Netzwerk übertragen werden. Es besteht die Möglichkeit einer App-Zurückweisung durch Apple, wenn diese in der App verwendet wird, in der die Zahlung oder persönliche Informationen des Kunden eingehen. – Karlos