Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iPad Mini 2 Crash #25

Closed
laszlo-major opened this issue Apr 13, 2018 · 7 comments
Closed

iPad Mini 2 Crash #25

laszlo-major opened this issue Apr 13, 2018 · 7 comments

Comments

@laszlo-major
Copy link

I'm getting a crash when trying to generate keys on an iPad Mini 2 running 11.0.0 with the log:

crash_info_entry_0
Fatal error: 'try!' expression unexpectedly raised an error: EllipticCurveKeyPair.EllipticCurveKeyPair.Error.underlying(message: "Could not generate keypair. Security probably doesn't like the access flags you provided. Specifically if this device doesn't have secure enclave and you pass .privateKeyUsage. it will produce this error.", error: Error Domain=NSOSStatusErrorDomain Code=-25293 "Could not generate keypair. Security probably doesn't like the access flags you provided. Specifically if this device doesn't have secure enclave and you pass .privateKeyUsage. it will produce this error." UserInfo={NSLocalizedRecoverySuggestion=See https://www.osstatus.com/search/results?platform=all&framework=all&search=-25293, NSLocalizedDescription=Could not generate keypair. Security probably doesn't like the access flags you provided. Specifically if this device doesn't have secure enclave and you pass .privateKeyUsage. it will produce this error.}): file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-902.0.48/src/swift/stdlib/public/core/ErrorType.swift, line 184

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.

@laszlo-major
Copy link
Author

laszlo-major commented Apr 19, 2018

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.

@hfossli
Copy link
Contributor

hfossli commented Apr 19, 2018

Hey! Thanks! Awesome feedback.

Do you have the stack trace of the crash? Why is there a «bang» («try!»)?

@laszlo-major
Copy link
Author

laszlo-major commented Apr 19, 2018

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.

@hfossli
Copy link
Contributor

hfossli commented Apr 19, 2018

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.

@laszlo-major
Copy link
Author

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!

@hfossli
Copy link
Contributor

hfossli commented Apr 19, 2018

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],
])

@hfossli
Copy link
Contributor

hfossli commented Apr 19, 2018

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)
    }()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants