0
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
        {
            switch challenge.protectionSpace.authenticationMethod {
            case NSURLAuthenticationMethodClientCertificate:
                let query: [String:Any] = [kSecAttrAccessGroup as String: kSecAttrAccessGroupToken,
                                           kSecAttrKeyClass as String : kSecAttrKeyClassPrivate,
                                           kSecClass as String : kSecClassIdentity,
                                           kSecReturnAttributes as String : kCFBooleanTrue as Any,
                                           kSecReturnRef as String: kCFBooleanTrue as Any,
                                           kSecMatchLimit as String: kSecMatchLimitAll,
                                           kSecReturnPersistentRef as String: kCFBooleanTrue as Any
                ]
                var result : AnyObject?
                let status = SecItemCopyMatching(query as CFDictionary, &result)
                
                guard status == errSecSuccess, let allItems = result as? [[String: Any]] else {
                    let errorDescription = SecCopyErrorMessageString(status, nil)
                    print(errorDescription as Any)
                    completionHandler(.cancelAuthenticationChallenge, nil)

                    return
                }
                
                let items = allItems.filter { item in
                    return (item["tkid"] as? String)?.starts(with: "Bundle ID") ?? false
//                    return true
                }

                // **items are the certificates which is already added in device**
                
                // Let user select which cert to use, handle pin entry and call the completion handler.
                let alert = UIAlertController.selectCertAndPinEntryAlert(certs: items, completionHandler: completionHandler)
                alert.show()

            case NSURLAuthenticationMethodServerTrust:
                let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
                completionHandler(URLSession.AuthChallengeDisposition.useCredential, credential);
            case NSURLAuthenticationMethodHTTPBasic:
                print("Basic auth")
            default:
                completionHandler(.useCredential, nil)
            }
        }

selectCertAndPinEntryAlert : this method allows user to choose the certificate which is already added in Keychain.

static func selectCertAndPinEntryAlert(certs: [[String : Any]], completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> UIAlertController {
        // Select cert UIAlertController.
        let alert = UIAlertController(title: "Select certificate", message: nil, preferredStyle: .actionSheet)
        certs.forEach { item in
            guard let certData = item["certdata"] as? Data else { return }
            guard let certificate = SecCertificateCreateWithData(nil, certData as CFData) else { return }
            alert.addAction(UIAlertAction(title: certificate.commonName,
                                          style: .default,
                                          handler: { action in
                // Pin entry UIAlertController created after the user selected one of the certs.
                let passwordAlert = UIAlertController(title: "Enter pin", message: nil, preferredStyle: .alert)
                passwordAlert.addTextField { textField in
                    textField.isSecureTextEntry = true
                }
                passwordAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
                    completionHandler(.cancelAuthenticationChallenge, nil)
                })
                passwordAlert.addAction(UIAlertAction(title: "Ok",
                                                      style: .default,
                                                      handler: { action in
                    guard let pin = passwordAlert.textFields?.first?.text else { completionHandler(.cancelAuthenticationChallenge, nil); return }
**                    let secIdentity = item["v_Ref"] as! SecIdentity
                    
                    let urlCredential = URLCredential(identity: secIdentity, certificates: nil, persistence: .forSession)**
                    
                    // If this doesn't return a UserDefaults something is broken in the project and we might as well crash.
                    UserDefaults(suiteName: "App Group which used by app")!.writePin(pin)
                    **completionHandler(.useCredential, urlCredential)**
                }))
                passwordAlert.show()
            }))
        }
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
            completionHandler(.cancelAuthenticationChallenge, nil)
        })
        return alert
    }

Please provide the suggestion what i am doing wrong. What code i need to change?

Note : I am using Yubikey for fetching certificates and storing it into the keychain. Later All the added certificate popup i ll get to choose one.

I have tried this code but when i am entring the key to access the certificate, WKWebView is not taking this certificate as further process and i am getting URL Credentials as null in response.

0 Answers0