Comments (7)
Let me add more details on this.
We have an own Password Input View
where user is unlocking the Authenticator with a Password
. Please note that this Password
is NOT the system (macOS) password, we use a custom algorithm to derivate an encryption key. That key is then stored in SecureEnclave. (there are more steps to get the encryption key but it is not important for our issue). We expect user to introduce the Password
and if some Biometric device is available (TouchId, FaceId, Watch) let them store the encryption key in SecureEnclave.
So what I understand is that you'd like a Valet API to access items in the SecureEnclave without allowing a fallback to passcode.
User can be confused about what Password should he use, system (macOS) or our custom Password
.
I'm not sure how this workflow is more secure than what we already provide, since the watch is ultimately unlocked with a passcode.
For me Unlock with Apple Watch
is like one more Biometrics hardware.
Our custom Password Input View
from valet.
Got it. So the issue at-hand isn't "more secure" or "less secure".
I think I need to dive deeper into how to accomplish "or" logic with the SecureEnclave – see #253 (comment) for more details. If I can get that working then we can pick #253 back up. That said, I'm not convinced that we need to support this use case within Valet.
It's entirely possible to accomplish your desired UI and security by using a LAContext
to guard access to the lookup within your application (we also have a TODO to make this kind of workflow easier, see #265). That's likely a less error-prone approach than storing items in different Valet objects based on the customer's current hardware.
from valet.
Hi @c128128! Thank you for filing a feature request. To move this request forward, I'm going to need a bit more information from you regarding what workflow you're asking us to support. I'd also love a bit more context on the screenshots above. Direct clarifying questions below:
- Can you state exactly what you're trying to accomplish? Per #253 (comment), our existing APIs do allow for unlocking the Secure Enclave via Watch. I'd love to better understand what additional or differentiated functionality you'd like us to support. If you can, please also share the motivation for this additional or differentiated functionality.
- Can you expand on the code snippets you provided above? I'm guessing that
accessControl: .userPresence
andaccessControl: .watch
are snippets of your code interacting directly with Security APIs rather than Valet APIs, but it'd be helpful if you could expand the snippet to provide a bit more context on how you're calling into Security's keychain APIs. - You said that "we can't Unlock the Item with System password": can you help me understand both what you want to happen and what API calls you were using that led to this unexpected or less-than-desired result? Or are you saying that your keychain use-case requires disabling unlock-via-password?
- What OS version are you testing the above on? And what version of Valet are you using?
Thanks again for using Valet and offering us guidance on how to improve our offerings!
from valet.
@dfed Thank you for reply.
-
Issue #253 was closed with comment that
Valet
already is permittingUnlock with Apple Watch
if you setaccessControl: .userPresence
. My screenshots shows that, the behaviour is different when settingaccessControl: .userPresence
andaccessControl: .watch
. In 1 case you can access the the item withmacOS
(system) password, and in the second case you can't. It depends on the user case, for instance, a Password Manager or in our case for an Authenticator it is critical. -
I have modified the Valet
4.1.2
to support this like:
// Created by Dan Federman on 9/18/17.
// Copyright © 2017 Square, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
@objc(VALSecureEnclaveAccessControl)
public enum SecureEnclaveAccessControl: Int, CustomStringConvertible, Equatable {
/// Access to keychain elements requires user presence verification via Touch ID, Face ID, or device Passcode. On macOS 10.15 and later, this element may also be accessed via a prompt on a paired watch. Keychain elements are still accessible by Touch ID even if fingers are added or removed. Touch ID does not have to be available or enrolled.
case userPresence = 1
/// Access to keychain elements requires user presence verification via Face ID, or any finger enrolled in Touch ID. Keychain elements remain accessible via Face ID or Touch ID after faces or fingers are added or removed. Face ID must be enabled with at least one face enrolled, or Touch ID must be available and at least one finger must be enrolled.
@available(macOS 10.12.1, *)
case biometricAny
/// Access to keychain elements requires user presence verification via the face currently enrolled in Face ID, or fingers currently enrolled in Touch ID. Previously written keychain elements become inaccessible when faces or fingers are added or removed. Face ID must be enabled with at least one face enrolled, or Touch ID must be available and at least one finger must be enrolled.
@available(macOS 10.12.1, *)
case biometricCurrentSet
/// Access to keychain elements requires user presence verification via device Passcode.
case devicePasscode
case watch
// MARK: CustomStringConvertible
public var description: String {
switch self {
case .userPresence:
/*
VALSecureEnclaveValet v1.0-v2.0.7 used UserPresence without a suffix – the concept of a customizable AccessControl was added in v2.1.
For backwards compatibility, do not append an access control suffix for UserPresence.
*/
return ""
case .biometricAny:
if #available(macOS 10.12.1, *) {
return "_AccessControlTouchIDAnyFingerprint"
} else {
assertionFailure(".biometricAny requires macOS 10.12.1.")
return ""
}
case .biometricCurrentSet:
if #available(macOS 10.12.1, *) {
return "_AccessControlTouchIDCurrentFingerprintSet"
} else {
assertionFailure(".biometricCurrentSet requires macOS 10.12.1.")
return ""
}
case .devicePasscode:
return "_AccessControlDevicePasscode"
case .watch:
return "_AccessControlWatch"
}
}
// MARK: Internal Properties
internal var secAccessControl: SecAccessControlCreateFlags {
switch self {
case .userPresence:
return .userPresence
case .biometricAny:
if #available(iOS 11.3, tvOS 11.3, watchOS 4.3, macOS 10.13.4, *) {
return .biometryAny
} else if #available(macOS 10.12.1, *) {
return .touchIDAny
} else {
assertionFailure(".biometricAny requires macOS 10.12.1.")
return .userPresence
}
case .biometricCurrentSet:
if #available(iOS 11.3, tvOS 11.3, watchOS 4.3, macOS 10.13.4, *) {
return .biometryCurrentSet
} else if #available(macOS 10.12.1, *) {
return .touchIDCurrentSet
} else {
assertionFailure(".biometricCurrentSet requires macOS 10.12.1.")
return .userPresence
}
case .devicePasscode:
if #available(macOS 10.11, *) {
return .devicePasscode
} else {
assertionFailure(".devicePasscode requires macOS 10.11.")
return .userPresence
}
case .watch:
#if targetEnvironment(macCatalyst)
return .watch
#else
assertionFailure(".watch is only available on macOS || macCatalyst")
return .userPresence
#endif
}
}
internal static func allValues() -> [SecureEnclaveAccessControl] {
var values: [SecureEnclaveAccessControl] = [
.userPresence,
.devicePasscode
]
if #available(macOS 10.12.1, *) {
values += [
.biometricAny,
.biometricCurrentSet,
]
}
return values
}
}
- I am using it like this:
private static func enclave(hardware: Biometry.Hardware) throws -> SecureEnclaveValet {
switch hardware {
case .touch, .face:
// swiftlint:disable:next force_unwrapping
return SecureEnclaveValet.valet(with: Identifier(nonEmpty: Biometry.SERVICE)!, accessControl: .biometricCurrentSet)
case .watch:
// swiftlint:disable:next force_unwrapping
return SecureEnclaveValet.valet(with: Identifier(nonEmpty: Biometry.SERVICE)!, accessControl: .watch)
case .none:
throw Error.message("Unvailable")
}
}
P.S: I am not an English native speaker. Feel free to ask, if something is unclear.
from valet.
Super helpful reply! Thank you!
So what I understand is that you'd like a Valet API to access items in the SecureEnclave without allowing a fallback to passcode. I'm not sure how this workflow is more secure than what we already provide, since the watch is ultimately unlocked with a passcode. Unlocking with watch is effectively an unlock with passcode since the watch is enabled only after you unlock it with your passcode (and watch passcodes are generally shorter and less secure than computer passwords).
That said, what do you want to happen if the customer does not have a watch? Are you hoping to fall back to another biometric?
from valet.
Thank you.
from valet.
This issue has been sitting open for awhile, and if I'm being honest I don't think I'm going to have time to invest in this functionality. Per my comment above – I believe utilizing a LAContext
is the best approach for this use case.
I'm going to close this issue out, but I do appreciate the suggestion and discussion above.
from valet.
Related Issues (20)
- Feature Request, Unlock with Apple Watch HOT 6
- Add convenience access methods for `Codable` types HOT 6
- .whenUnlocked vs .afterFirstUnlock HOT 3
- Create new KeyChain Option HOT 5
- SecKeychainAddCallback(_:_:_:) along with Valet HOT 4
- Enable customization of biometrics prompt with application-specific fallback HOT 26
- Unit tests fail on tvOS 14 HOT 4
- Tips on building and running the sample app? HOT 1
- Keychain Sharing between iOS App and Apple Watch Extension HOT 6
- Documentation for `afterFirstUnlockThisDeviceOnly` wrong? HOT 1
- iOS 15 crash on `specialized static SecItem.copy<A>(matching:)` HOT 18
- iOS 16 build error HOT 6
- tvOS target doesn't compile with Xcode 14.0 beta HOT 8
- Deprecation warnings when targeting iOS 14+ HOT 4
- (Some folks) await async support HOT 5
- error: non-void function does not return a value [-Werror,-Wreturn-type] HOT 2
- No way to invalidate() HOT 1
- Support for cryptographic key item (kSecClassKey) HOT 2
- Could not find module 'Valet' for target 'x86_64-apple-ios-simulator' HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from valet.