2015-06-18 3 views
5

Ho appena aggiornato il mio codice a Swift 2.0 per funzionare con Xcode 7. La mia app esegue l'autenticazione NSURLAuthenticationMethodServerTrust e NSURLAuthenticationMethodClientCertificate.Autenticazione server in Swift 2.0 e XCode 7 interrotta

Il problema è NSURLAuthenticationMethodServerTrust l'autenticazione ha smesso di funzionare sul mio simulatore, ma funziona ancora sul mio dispositivo di test con iOS 8.3. Oltre al mio vecchio progetto, che non è Swift 2.0, funziona ancora.

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

errore recuperato dal 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] 

sto ancora il targeting iOS 8.0 per la distribuzione.

Questo è come gestire la sfida di autenticazione (utilizzando un certificato firmato di auto):

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

    } 

risposta

2

Non è possibile ignorare il livello TLS. Si prega di trovare la risposta qui sotto che ha funzionato per me utilizzando il certificato autofirmato.

seguito sono le modifiche al codice che funziona bene con autofirmato certificato 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; 
} 

cambiamenti fatti in file 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

vostro simulatore è la maggior parte delle iOS probabile che eseguono 9 poi. In iOS 9, TLS 1.2 è applicato. Se non lo stai utilizzando, le tue richieste falliranno.

Per ulteriori informazioni, consultare this post.

è possibile ignorare che mettendo questo nel tuo Info.plist:

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

ma è semplicemente una soluzione temporanea fino a quando è possibile implementare TLS 1.2.

+0

Grazie. Solo un (probabilmente ovvio commento - per newb relativi come me) - metti questo in fondo al file, facendo attenzione ad avere ancora le ultime due righe, e dopo di esso. I miei primi tentativi di posizionarlo vicino alla parte superiore hanno influenzato la formattazione XML (riceverai un errore "Info.plist non nel formato corretto" se lo inserisci in modo errato). – user3741598

0

ho avuto lo stesso problema con iOS9 & Xcode 7 Basta aggiungere :

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

a file plist. Funziona ma è una soluzione temporanea finché non è possibile implementare TLS 1.2.

+0

Le righe di codice di cui sopra bypasseranno semplicemente il livello di sicurezza TLS e questo non è accettabile se si sta lavorando sull'app in cui le informazioni di sicurezza del client passano attraverso la rete. Ci sono possibilità di rifiuto dell'app da parte di Apple se questa viene utilizzata nell'app in cui vengono fornite le informazioni personali relative ai pagamenti o ai clienti. – Karlos