agens-no / EllipticCurveKeyPair

Sign, verify, encrypt and decrypt using the Secure Enclave
Other
708 stars 114 forks source link

Dismiss TouchID authentication #5

Open Vabs28 opened 6 years ago

Vabs28 commented 6 years ago

Hi

I am not sure if this is possible. Can we cancel TouchID authentication happening on decrypt operation if we dont want to proceed? LAContext has a method "invalidate" which invalidates LAContext and throws LAErrorAppCancel error.

e.g. We prompt user to authenticate using TouchID as soon as app is opened. We also make a background call to check if user is running on latest app. If user is running on old version then we cancel TouchID operation and show a message which says "Please update app to latest version."

hfossli commented 6 years ago

I’m really not sure. https://youtu.be/fpaQpyU_QiM

hfossli commented 6 years ago

Why do you want to cancel? What is the use case?

Vabs28 commented 6 years ago

e.g. We prompt the user to authenticate using TouchID as soon as the app is opened. The app may also receive some authentication messages that he needs to action (select Accept/Reject on 2FA messages).

If the app receives an Authentication messages then we cancel the TouchID operation and show the authentication message.

hfossli commented 6 years ago

I have rewritten some of the code so I'm now able to pass a LAContext to sign and decrypt. Sad thing is that I don't get to dismiss the LAContext once it is showing the fingerprint dialog. Do you know how?

Example

import UIKit
import LocalAuthentication

class ViewController: UIViewController {

    var context: LAContext! = LAContext()

    func createAccessControl(protection: CFString = kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, flags: SecAccessControlCreateFlags = [.userPresence, .privateKeyUsage]) -> SecAccessControl {
        var error: Unmanaged<CFError>?
        let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protection, flags, &error)
        return accessControl!
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        delay(1.0, queue: .main) {
            self.decrypt()
        }
    }

    func decrypt() {

        let accessControl = createAccessControl()
        context.evaluateAccessControl(accessControl, operation: .useKeySign, localizedReason: "Sign") { (success, error) in
            DispatchQueue.main.async {
                if success {
                    let alert = UIAlertController(title: "Authenticated", message: "Ready to sign/decrypt", preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
                    self.show(alert, sender: nil)
                } else {
                    let alert = UIAlertController(title: "Failed to authenticate", message: "Error: \(error!)", preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
                    self.show(alert, sender: nil)
                }
            }
        }

        delay(3.0, queue: .main) {
            self.context.invalidate()
        }
    }
}

func delay( _ delay: Double, queue: DispatchQueue, completion: @escaping () -> () ) {
    queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
        completion()
    }
}

It doesn't seem promising.

hfossli commented 6 years ago

If you are able to remove the dialog then I'll be happy to finish the rewrite to support LAContext.

Vabs28 commented 6 years ago

Hi I am new to Swift development. I also tried similar thing, it doesn't close TouchID dialog. Rather calling invalidate method doesn't do anything, you can still authenticate yourself with correct fingerprint.

hfossli commented 6 years ago

So then I guess this is not possible... sadly. If you find a way to close it I’ll be more than happy to change the library

hfossli commented 6 years ago

I have pushed my code to master. Whenever you sign or decrypt you will have the possibility of passing a LAContext.

Like this

let signature = try manager.sign(digest, authenticationContext: context)
hfossli commented 6 years ago

In this archive you'll find two files and you'll see there's a bug with LAContext

Bug.zip

Vabs28 commented 6 years ago

Thanks a lot

hfossli commented 6 years ago

http://www.openradar.me/35069937

hfossli commented 6 years ago

Apple thinks this is fixed in latest GM. Are you, @Vabs28, able to check this? img_0331

hfossli commented 6 years ago

It seems apple solved this when working with the LAContext directly. It doesn't work for me when the LAContext is presented by Security framework for some reason.