Closed laszlo-major closed 6 years ago
It seems the it being an iPad mini and the doubts about secure enclave were a bit misleading - I can reproduce the crash with any device after factory resetting it end NOT setting a passcode. I'm confused about why this would matter, if I'm not using the 'kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly' flag. Changing protection on the private access to 'kSecAttrAccessibleAlwaysThisDeviceOnly' also makes no difference.
Hey! Thanks! Awesome feedback.
Do you have the stack trace of the crash? Why is there a «bang» («try!»)?
The crash is actually just the symptom as I prefer failing fast, and I would have never noticed otherwise in a dev environment where signing isn't validated properly, but proceeding without the keys is not viable.
The failure happens at in the library
let status = SecKeyGeneratePair(query as CFDictionary, &publicOptional, &privateOptional)
With the query
2018-04-19 09:17:09:127 App[330:27259] SecItemCopyMatching: ["kcls": 0, "class": keys, "labl": "no.key.public.3", "r_Ref": true] 2018-04-19 09:17:27:617 OnlineBank[330:27259] SecKeyGeneratePair: ["bsiz": 256, "type": "73", "private": ["u_AuthUI": u_AuthUIA, "u_AuthCtx": <LAContext: 0x1c4877600>, "labl": "no.key.private.3", "perm": true, "accc": <SecAccessControlRef: 0x1c02269e0>], "public": ["labl": "no.key.public.3", "pdmn": dku]]
I'm a bit confused as to how and why this work in the simulator without any security with the .userPresence flag, but not on devices. And "hasSecureEnclave" is actually returning false on an iPhone 7 without passcode, because I guess LAContext can't evaluate anything in this state.
Personally, I don't understand why anyone would use a phone without a passcode, but it's getting pretty annoying that I can't make it work regardless :)
NOTE: if I force .privateKeyUsage AND .secureEnclave as token, it succeeds. It only fails with .secureEnclaveIfAvailable because in that case it switches to keychain, as 'hasTouchId' evaluates to false.
Thanks again for sharing your insight. I haven’t tested on every device with various setups so this is very valuable.
In this case, where user doesnt have any passcode, what makes sense for your application? In my case we demand passcode for security reasons.
Hm, I guess warning and blocking the user, demanding a passcode would be fine, especially since there's a very small percentage of users with devices with no passcode, and also no secure enclave, I would assume.
So in conclusion, there's nothing wrong with the library, except maybe the check for 'hasSecureEnclave' actually returning false on devices without passcode.
Thanks for the nice library, it really makes the iOS crypto more palatable!
I think it is possible to ask for a user given password even though the device hasn't any passcode. Instead of .userPresence
you may use .applicationPassword
.
On way the library could solve these problems is by giving fallback mechanisms if some configuration isn't working. Rough example
static let privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: .firstUnlockThisDeviceOnly, flagsByPriority: [
[.userPresence, .privateKeyUsage],
[.userPresence],
[.applicationPassword],
])
Or maybe
struct Shared {
static let config = EllipticCurveKeyPair.Config(
publicLabel: "no.agens.sign.public",
privateLabel: "no.agens.sign.private",
operationPrompt: "Sign transaction",
publicKeyAccessControl: [
EllipticCurveKeyPair.AccessControl(.accessibleAlwaysThisDeviceOnly, flags: [])
],
privateKeyAccessControl: [
EllipticCurveKeyPair.AccessControl(.firstUnlockThisDeviceOnly, flagsByPriority: [.userPresence, .privateKeyUsage]),
EllipticCurveKeyPair.AccessControl(.firstUnlockThisDeviceOnly, flagsByPriority: [.userPresence])
EllipticCurveKeyPair.AccessControl(.firstUnlockThisDeviceOnly, flagsByPriority: [.applicationPassword])
],
token: .secureEnclaveIfAvailable)
static let keypair: EllipticCurveKeyPair.Manager = {
EllipticCurveKeyPair.logger = { print($0) }
return EllipticCurveKeyPair.Manager(config: config)
}()
}
I'm getting a crash when trying to generate keys on an iPad Mini 2 running 11.0.0 with the log:
This device does not have touchID from what I see, so I guess also no secure enclave?
The config I'm using is:
static let handler: EllipticCurveKeyPair.Manager = { EllipticCurveKeyPair.logger = { DDLogDebug($0) } let publicAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAlwaysThisDeviceOnly, flags: []) let privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, flags: { return EllipticCurveKeyPair.Device.hasSecureEnclave ? [.userPresence, .privateKeyUsage] : [.userPresence] }()) let config = EllipticCurveKeyPair.Config( publicLabel: PUBLIC_KEY_LABEL, privateLabel:PRIVATE_KEY_LABEL, operationPrompt: "Decrypt message", publicKeyAccessControl: publicAccessControl, privateKeyAccessControl: privateAccessControl, token: .secureEnclaveIfAvailable) return EllipticCurveKeyPair.Manager(config: config) }()
Running latest commit of master.