2015-06-18 12 views
5

Właśnie zaktualizowałem swój kod do Swift 2.0, aby działał z Xcode 7. Moja aplikacja wykonuje uwierzytelnienie NSURLAuthenticationMethodServerTrust i NSURLAuthenticationMethodClientCertificate.Uwierzytelnianie serwera w Swift 2.0 i XCode 7 zerwane

Problem polega na tym, że uwierzytelnianie przestało działać na moim symulatorze - ale nadal działa na moim urządzeniu testowym z iOS 8.3. Poza tym mój stary projekt, który nie jest Swiftem 2.0, również działa.

Błąd: NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

Błąd pobierane z 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] 

ja wciąż kierowania iOS 8.0 do wdrożenia.

ten sposób obsłużyć wyzwanie uwierzytelnienia (przy użyciu certyfikatu z podpisem własnym):

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

    } 

Odpowiedz

2

Nie pominięto warstwy TLS. Poniżej znajdziesz odpowiedź, która sprawdzała się przy korzystaniu z certyfikatu z podpisem własnym.

Poniżej przedstawiono zmiany w kodzie, który współpracuje z podpisem własnym certyfikat 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; 
} 

zmian dokonanych w pliku 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> 
17

symulatora jest najprawdopodobniej z systemem iOS 9 wtedy. W systemie iOS 9 egzekwowany jest protokół TLS 1.2. Jeśli go nie używasz, Twoje żądania zakończą się niepowodzeniem.

Aby uzyskać więcej informacji, sprawdź numer this post.

można ominąć go umieszczając to w swoim Info.plist:

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

ale jest to po prostu tymczasowe obejście aż można wdrożyć TLS 1.2.

+0

Dzięki. Po prostu (prawdopodobnie oczywisty komentarz - w przypadku względnych newbów, takich jak ja) - umieść to na dole pliku, uważając, aby po nim zachować dwie ostatnie linie: i . Moje pierwsze próby umieszczenia go w pobliży zakłóciły formatowanie XML (otrzymasz komunikat o błędzie "Info.plist w niewłaściwym formacie", jeśli umieścisz go niepoprawnie). – user3741598

0

miałem ten sam problem z iOS9 & xcode 7 Wystarczy dodać :

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

do plik plist. Działa, ale jest to tymczasowe obejście, dopóki nie można zaimplementować protokołu TLS 1.2.

+0

Powyższe wiersze kodu pominą po prostu warstwę zabezpieczeń TLS, co jest nie do przyjęcia, jeśli pracujesz nad aplikacją, w której przechodzą bezpieczne informacje o kliencie. Istnieje możliwość odrzucenia aplikacji przez firmę Apple, jeśli jest ona używana w aplikacji, w której pojawia się powiązanie z płatnością lub dane osobowe klienta. – Karlos

Powiązane problemy