2015-11-05 4 views
2

Я хочу проверить подлинность сертификата клиента в своем приложении. Я получаю следующие ошибки в функции didReceiveChallenge. Я нашел это решение в этом link.Проверка подлинности сертификата клиента в swift2

enter image description here

Мой didReceiveChallenge FUNC код:

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("example.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)! 

     var p12items : Unmanaged<CFArray>? 

     let index: CFIndex = 1 
     let password: CFString = "password" 

     var values = [unsafeAddressOf(password)] 
     var keys = [unsafeAddressOf(kSecImportExportPassphrase)] 

     var keyCallbacks = kCFTypeDictionaryKeyCallBacks 
     var valueCallbacks = kCFTypeDictionaryValueCallBacks 

     let length: CFIndex = PKCS12Data.length 
     let p12CfData: CFData = CFDataCreate(kCFAllocatorDefault, UnsafePointer<UInt8>(PKCS12Data.bytes), length) 

     let options = CFDictionaryCreate(kCFAllocatorDefault, &keys, &values, index, &keyCallbacks, &valueCallbacks) 
     let result = SecPKCS12Import(p12CfData, options, p12items) 

     if result == noErr { 

      let idIndex: CFIndex = 0 
      var items = p12items?.takeRetainedValue() 
      var identityDict = CFArrayGetValueAtIndex(items!, idIndex) 

      var keyAddress = unsafeAddressOf(kSecImportItemIdentity) 
      var identityApp: SecIdentityRef = CFDictionaryGetValue(identityDict, keyAddress) 
      var certRef : Unmanaged<SecCertificateRef>? 
      SecIdentityCopyCertificate(identityApp, certRef) 

      var cert: SecCertificateRef = certRef!.takeRetainedValue() 
      var certArray = [unsafeAddressOf(cert)] 
      var arrayCallback = kCFTypeArrayCallBacks 
      var myCerts: CFArrayRef = CFArrayCreate(kCFAllocatorDefault, &certArray, index, &arrayCallback); 


     let urlCredential:NSURLCredential = NSURLCredential(
      identity: identityApp, 
      certificates: myCerts as [AnyObject], 
      persistence: NSURLCredentialPersistence.Permanent) 

     challenge.sender!.useCredential(urlCredential ,forAuthenticationChallenge:challenge) 

    } 


} 

Любой пример для проверки подлинности клиента в NSURLSession будет полезно. Спасибо заранее.

ответ

4

Ниже приведены изменения кода, который отлично работает с сертификатом, 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> 
2

Для тех, кто заинтересован, это небольшая модификация из код @Karlos, который совместим с Swift 3.0:

fileprivate func extractCredential(_ certData: Data) -> Credential? { 
    // REF.: itx | EB418667-6ECD-4D22-B31E-0BB4000849A2 
    var credential: Credential! 

    let key = kSecImportExportPassphrase as NSString 

    let importPasswordOption:NSDictionary = [key as NSString:cerPassword] 
    var items: CFArray? 
    let securityError = SecPKCS12Import(certData as CFData, importPasswordOption, &items) 

    if securityError == errSecSuccess { 
     let certItems = items as CFArray! 
     let certItemsArray = (certItems as! NSArray) 
     let dict = certItemsArray.first 

     guard let certEntry = certItemsArray.firstObject as? [String:AnyObject] else { fatalError() } 

     // Identity 
     let identityPointer = certEntry["identity"]; 
     let secIdentityRef = identityPointer as! SecIdentity!; 

     // Trust 
     let trustPointer = certEntry["trust"]; 
     let trustRef = trustPointer as! SecTrust; 

     // Certificates 
     let chainPointer = certEntry["chain"]; 

     credential = Credential(identityRef: secIdentityRef!, trust: trustRef, certArray: chainPointer!); 
    } 

    return credential; 
} 
+0

Nice one Albert – Karlos

Смежные вопросы