|
@@ -157,44 +157,77 @@ public struct AuthenticationPolicy: OptionSet {
|
|
|
have to be available or enrolled. Item is still accessible by Touch ID
|
|
|
even if fingers are added or removed.
|
|
|
*/
|
|
|
- @available(iOS 8.0, OSX 10.10, *)
|
|
|
- @available(watchOS, unavailable)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ @available(OSX 10.10, *)
|
|
|
+ @available(watchOS 2.0, *)
|
|
|
+ @available(tvOS 8.0, *)
|
|
|
public static let userPresence = AuthenticationPolicy(rawValue: 1 << 0)
|
|
|
|
|
|
/**
|
|
|
- Constraint: Touch ID (any finger). Touch ID must be available and
|
|
|
- at least one finger must be enrolled. Item is still accessible by
|
|
|
- Touch ID even if fingers are added or removed.
|
|
|
+ Constraint: Touch ID (any finger) or Face ID. Touch ID or Face ID must be available. With Touch ID
|
|
|
+ at least one finger must be enrolled. With Face ID user has to be enrolled. Item is still accessible by Touch ID even
|
|
|
+ if fingers are added or removed. Item is still accessible by Face ID if user is re-enrolled.
|
|
|
*/
|
|
|
- @available(iOS 9.0, *)
|
|
|
- @available(OSX, unavailable)
|
|
|
- @available(watchOS, unavailable)
|
|
|
+ @available(iOS 11.3, *)
|
|
|
+ @available(OSX 10.13.4, *)
|
|
|
+ @available(watchOS 4.3, *)
|
|
|
+ @available(tvOS 11.3, *)
|
|
|
+ public static let biometryAny = AuthenticationPolicy(rawValue: 1 << 1)
|
|
|
+
|
|
|
+ /**
|
|
|
+ Deprecated, please use biometryAny instead.
|
|
|
+ */
|
|
|
+ @available(iOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryAny")
|
|
|
+ @available(OSX, introduced: 10.12.1, deprecated: 10.13.4, renamed: "biometryAny")
|
|
|
+ @available(watchOS, introduced: 2.0, deprecated: 4.3, renamed: "biometryAny")
|
|
|
+ @available(tvOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryAny")
|
|
|
public static let touchIDAny = AuthenticationPolicy(rawValue: 1 << 1)
|
|
|
|
|
|
/**
|
|
|
- Constraint: Touch ID from the set of currently enrolled fingers.
|
|
|
- Touch ID must be available and at least one finger must be enrolled.
|
|
|
- When fingers are added or removed, the item is invalidated.
|
|
|
+ Constraint: Touch ID from the set of currently enrolled fingers. Touch ID must be available and at least one finger must
|
|
|
+ be enrolled. When fingers are added or removed, the item is invalidated. When Face ID is re-enrolled this item is invalidated.
|
|
|
*/
|
|
|
- @available(iOS 9.0, *)
|
|
|
- @available(OSX, unavailable)
|
|
|
- @available(watchOS, unavailable)
|
|
|
+ @available(iOS 11.3, *)
|
|
|
+ @available(OSX 10.13.4, *)
|
|
|
+ @available(watchOS 4.3, *)
|
|
|
+ @available(tvOS 11.3, *)
|
|
|
+ public static let biometryCurrentSet = AuthenticationPolicy(rawValue: 1 << 3)
|
|
|
+
|
|
|
+ /**
|
|
|
+ Deprecated, please use biometryCurrentSet instead.
|
|
|
+ */
|
|
|
+ @available(iOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryCurrentSet")
|
|
|
+ @available(OSX, introduced: 10.12.1, deprecated: 10.13.4, renamed: "biometryCurrentSet")
|
|
|
+ @available(watchOS, introduced: 2.0, deprecated: 4.3, renamed: "biometryCurrentSet")
|
|
|
+ @available(tvOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryCurrentSet")
|
|
|
public static let touchIDCurrentSet = AuthenticationPolicy(rawValue: 1 << 3)
|
|
|
|
|
|
/**
|
|
|
Constraint: Device passcode
|
|
|
*/
|
|
|
- @available(iOS 9.0, OSX 10.11, *)
|
|
|
- @available(watchOS, unavailable)
|
|
|
+ @available(iOS 9.0, *)
|
|
|
+ @available(OSX 10.11, *)
|
|
|
+ @available(watchOS 2.0, *)
|
|
|
+ @available(tvOS 9.0, *)
|
|
|
public static let devicePasscode = AuthenticationPolicy(rawValue: 1 << 4)
|
|
|
|
|
|
+ /**
|
|
|
+ Constraint: Watch
|
|
|
+ */
|
|
|
+ @available(iOS, unavailable)
|
|
|
+ @available(OSX 10.15, *)
|
|
|
+ @available(watchOS, unavailable)
|
|
|
+ @available(tvOS, unavailable)
|
|
|
+ public static let watch = AuthenticationPolicy(rawValue: 1 << 5)
|
|
|
+
|
|
|
/**
|
|
|
Constraint logic operation: when using more than one constraint,
|
|
|
at least one of them must be satisfied.
|
|
|
*/
|
|
|
@available(iOS 9.0, *)
|
|
|
- @available(OSX, unavailable)
|
|
|
- @available(watchOS, unavailable)
|
|
|
+ @available(OSX 10.12.1, *)
|
|
|
+ @available(watchOS 2.0, *)
|
|
|
+ @available(tvOS 9.0, *)
|
|
|
public static let or = AuthenticationPolicy(rawValue: 1 << 14)
|
|
|
|
|
|
/**
|
|
@@ -202,16 +235,18 @@ public struct AuthenticationPolicy: OptionSet {
|
|
|
all must be satisfied.
|
|
|
*/
|
|
|
@available(iOS 9.0, *)
|
|
|
- @available(OSX, unavailable)
|
|
|
- @available(watchOS, unavailable)
|
|
|
+ @available(OSX 10.12.1, *)
|
|
|
+ @available(watchOS 2.0, *)
|
|
|
+ @available(tvOS 9.0, *)
|
|
|
public static let and = AuthenticationPolicy(rawValue: 1 << 15)
|
|
|
|
|
|
/**
|
|
|
Create access control for private key operations (i.e. sign operation)
|
|
|
*/
|
|
|
@available(iOS 9.0, *)
|
|
|
- @available(OSX, unavailable)
|
|
|
- @available(watchOS, unavailable)
|
|
|
+ @available(OSX 10.12.1, *)
|
|
|
+ @available(watchOS 2.0, *)
|
|
|
+ @available(tvOS 9.0, *)
|
|
|
public static let privateKeyUsage = AuthenticationPolicy(rawValue: 1 << 30)
|
|
|
|
|
|
/**
|
|
@@ -219,8 +254,9 @@ public struct AuthenticationPolicy: OptionSet {
|
|
|
This is not a constraint but additional item encryption mechanism.
|
|
|
*/
|
|
|
@available(iOS 9.0, *)
|
|
|
- @available(OSX, unavailable)
|
|
|
- @available(watchOS, unavailable)
|
|
|
+ @available(OSX 10.12.1, *)
|
|
|
+ @available(watchOS 2.0, *)
|
|
|
+ @available(tvOS 9.0, *)
|
|
|
public static let applicationPassword = AuthenticationPolicy(rawValue: 1 << 31)
|
|
|
|
|
|
#if swift(>=2.3)
|
|
@@ -742,14 +778,35 @@ public final class Keychain {
|
|
|
|
|
|
// MARK:
|
|
|
|
|
|
- public func contains(_ key: String) throws -> Bool {
|
|
|
+ public func contains(_ key: String, withoutAuthenticationUI: Bool = false) throws -> Bool {
|
|
|
var query = options.query()
|
|
|
query[AttributeAccount] = key
|
|
|
|
|
|
+ if withoutAuthenticationUI {
|
|
|
+ #if os(iOS) || os(watchOS) || os(tvOS)
|
|
|
+ if #available(iOS 9.0, *) {
|
|
|
+ query[UseAuthenticationUI] = UseAuthenticationUIFail
|
|
|
+ } else {
|
|
|
+ query[UseNoAuthenticationUI] = kCFBooleanTrue
|
|
|
+ }
|
|
|
+ #else
|
|
|
+ if #available(OSX 10.11, *) {
|
|
|
+ query[UseAuthenticationUI] = UseAuthenticationUIFail
|
|
|
+ } else if #available(OSX 10.10, *) {
|
|
|
+ query[UseNoAuthenticationUI] = kCFBooleanTrue
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
let status = SecItemCopyMatching(query as CFDictionary, nil)
|
|
|
switch status {
|
|
|
case errSecSuccess:
|
|
|
- return true
|
|
|
+ return true
|
|
|
+ case errSecInteractionNotAllowed:
|
|
|
+ if withoutAuthenticationUI {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
case errSecItemNotFound:
|
|
|
return false
|
|
|
default:
|
|
@@ -1060,7 +1117,9 @@ public final class Keychain {
|
|
|
@discardableResult
|
|
|
fileprivate class func securityError(status: OSStatus) -> Error {
|
|
|
let error = Status(status: status)
|
|
|
- print("OSStatus error:[\(error.errorCode)] \(error.description)")
|
|
|
+ if error != .userCanceled {
|
|
|
+ print("OSStatus error:[\(error.errorCode)] \(error.description)")
|
|
|
+ }
|
|
|
|
|
|
return error
|
|
|
}
|
|
@@ -1144,32 +1203,28 @@ private let ValueRef = String(kSecValueRef)
|
|
|
private let ValuePersistentRef = String(kSecValuePersistentRef)
|
|
|
|
|
|
/** Other Constants */
|
|
|
-@available(iOS 8.0, OSX 10.10, *)
|
|
|
+@available(iOS 8.0, OSX 10.10, tvOS 8.0, *)
|
|
|
private let UseOperationPrompt = String(kSecUseOperationPrompt)
|
|
|
|
|
|
-#if os(iOS)
|
|
|
@available(iOS, introduced: 8.0, deprecated: 9.0, message: "Use a UseAuthenticationUI instead.")
|
|
|
+@available(OSX, introduced: 10.10, deprecated: 10.11, message: "Use UseAuthenticationUI instead.")
|
|
|
+@available(watchOS, introduced: 2.0, deprecated: 2.0, message: "Use UseAuthenticationUI instead.")
|
|
|
+@available(tvOS, introduced: 8.0, deprecated: 9.0, message: "Use UseAuthenticationUI instead.")
|
|
|
private let UseNoAuthenticationUI = String(kSecUseNoAuthenticationUI)
|
|
|
-#endif
|
|
|
|
|
|
-@available(iOS 9.0, OSX 10.11, *)
|
|
|
-@available(watchOS, unavailable)
|
|
|
+@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
|
|
|
private let UseAuthenticationUI = String(kSecUseAuthenticationUI)
|
|
|
|
|
|
-@available(iOS 9.0, OSX 10.11, *)
|
|
|
-@available(watchOS, unavailable)
|
|
|
+@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
|
|
|
private let UseAuthenticationContext = String(kSecUseAuthenticationContext)
|
|
|
|
|
|
-@available(iOS 9.0, OSX 10.11, *)
|
|
|
-@available(watchOS, unavailable)
|
|
|
+@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
|
|
|
private let UseAuthenticationUIAllow = String(kSecUseAuthenticationUIAllow)
|
|
|
|
|
|
-@available(iOS 9.0, OSX 10.11, *)
|
|
|
-@available(watchOS, unavailable)
|
|
|
+@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
|
|
|
private let UseAuthenticationUIFail = String(kSecUseAuthenticationUIFail)
|
|
|
|
|
|
-@available(iOS 9.0, OSX 10.11, *)
|
|
|
-@available(watchOS, unavailable)
|
|
|
+@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
|
|
|
private let UseAuthenticationUISkip = String(kSecUseAuthenticationUISkip)
|
|
|
|
|
|
#if os(iOS)
|