|
@@ -0,0 +1,3074 @@
|
|
|
+//
|
|
|
+// Keychain.swift
|
|
|
+// KeychainAccess
|
|
|
+//
|
|
|
+// Created by kishikawa katsumi on 2014/12/24.
|
|
|
+// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
|
|
|
+//
|
|
|
+// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
+// of this software and associated documentation files (the "Software"), to deal
|
|
|
+// in the Software without restriction, including without limitation the rights
|
|
|
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
+// copies of the Software, and to permit persons to whom the Software is
|
|
|
+// furnished to do so, subject to the following conditions:
|
|
|
+//
|
|
|
+// The above copyright notice and this permission notice shall be included in
|
|
|
+// all copies or substantial portions of the Software.
|
|
|
+//
|
|
|
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
+// THE SOFTWARE.
|
|
|
+
|
|
|
+import Foundation
|
|
|
+import Security
|
|
|
+#if os(iOS) || os(OSX)
|
|
|
+import LocalAuthentication
|
|
|
+#endif
|
|
|
+
|
|
|
+public let KeychainAccessErrorDomain = "com.kishikawakatsumi.KeychainAccess.error"
|
|
|
+
|
|
|
+public enum ItemClass {
|
|
|
+ case genericPassword
|
|
|
+ case internetPassword
|
|
|
+}
|
|
|
+
|
|
|
+public enum ProtocolType {
|
|
|
+ case ftp
|
|
|
+ case ftpAccount
|
|
|
+ case http
|
|
|
+ case irc
|
|
|
+ case nntp
|
|
|
+ case pop3
|
|
|
+ case smtp
|
|
|
+ case socks
|
|
|
+ case imap
|
|
|
+ case ldap
|
|
|
+ case appleTalk
|
|
|
+ case afp
|
|
|
+ case telnet
|
|
|
+ case ssh
|
|
|
+ case ftps
|
|
|
+ case https
|
|
|
+ case httpProxy
|
|
|
+ case httpsProxy
|
|
|
+ case ftpProxy
|
|
|
+ case smb
|
|
|
+ case rtsp
|
|
|
+ case rtspProxy
|
|
|
+ case daap
|
|
|
+ case eppc
|
|
|
+ case ipp
|
|
|
+ case nntps
|
|
|
+ case ldaps
|
|
|
+ case telnetS
|
|
|
+ case imaps
|
|
|
+ case ircs
|
|
|
+ case pop3S
|
|
|
+}
|
|
|
+
|
|
|
+public enum AuthenticationType {
|
|
|
+ case ntlm
|
|
|
+ case msn
|
|
|
+ case dpa
|
|
|
+ case rpa
|
|
|
+ case httpBasic
|
|
|
+ case httpDigest
|
|
|
+ case htmlForm
|
|
|
+ case `default`
|
|
|
+}
|
|
|
+
|
|
|
+public enum Accessibility {
|
|
|
+ /**
|
|
|
+ Item data can only be accessed
|
|
|
+ while the device is unlocked. This is recommended for items that only
|
|
|
+ need be accesible while the application is in the foreground. Items
|
|
|
+ with this attribute will migrate to a new device when using encrypted
|
|
|
+ backups.
|
|
|
+ */
|
|
|
+ case whenUnlocked
|
|
|
+
|
|
|
+ /**
|
|
|
+ Item data can only be
|
|
|
+ accessed once the device has been unlocked after a restart. This is
|
|
|
+ recommended for items that need to be accesible by background
|
|
|
+ applications. Items with this attribute will migrate to a new device
|
|
|
+ when using encrypted backups.
|
|
|
+ */
|
|
|
+ case afterFirstUnlock
|
|
|
+
|
|
|
+ /**
|
|
|
+ Item data can always be accessed
|
|
|
+ regardless of the lock state of the device. This is not recommended
|
|
|
+ for anything except system use. Items with this attribute will migrate
|
|
|
+ to a new device when using encrypted backups.
|
|
|
+ */
|
|
|
+ @available(macCatalyst, unavailable)
|
|
|
+ case always
|
|
|
+
|
|
|
+ /**
|
|
|
+ Item data can
|
|
|
+ only be accessed while the device is unlocked. This class is only
|
|
|
+ available if a passcode is set on the device. This is recommended for
|
|
|
+ items that only need to be accessible while the application is in the
|
|
|
+ foreground. Items with this attribute will never migrate to a new
|
|
|
+ device, so after a backup is restored to a new device, these items
|
|
|
+ will be missing. No items can be stored in this class on devices
|
|
|
+ without a passcode. Disabling the device passcode will cause all
|
|
|
+ items in this class to be deleted.
|
|
|
+ */
|
|
|
+ @available(iOS 8.0, OSX 10.10, *)
|
|
|
+ case whenPasscodeSetThisDeviceOnly
|
|
|
+
|
|
|
+ /**
|
|
|
+ Item data can only
|
|
|
+ be accessed while the device is unlocked. This is recommended for items
|
|
|
+ that only need be accesible while the application is in the foreground.
|
|
|
+ Items with this attribute will never migrate to a new device, so after
|
|
|
+ a backup is restored to a new device, these items will be missing.
|
|
|
+ */
|
|
|
+ case whenUnlockedThisDeviceOnly
|
|
|
+
|
|
|
+ /**
|
|
|
+ Item data can
|
|
|
+ only be accessed once the device has been unlocked after a restart.
|
|
|
+ This is recommended for items that need to be accessible by background
|
|
|
+ applications. Items with this attribute will never migrate to a new
|
|
|
+ device, so after a backup is restored to a new device these items will
|
|
|
+ be missing.
|
|
|
+ */
|
|
|
+ case afterFirstUnlockThisDeviceOnly
|
|
|
+
|
|
|
+ /**
|
|
|
+ Item data can always
|
|
|
+ be accessed regardless of the lock state of the device. This option
|
|
|
+ is not recommended for anything except system use. Items with this
|
|
|
+ attribute will never migrate to a new device, so after a backup is
|
|
|
+ restored to a new device, these items will be missing.
|
|
|
+ */
|
|
|
+ @available(macCatalyst, unavailable)
|
|
|
+ case alwaysThisDeviceOnly
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Predefined item attribute constants used to get or set values
|
|
|
+ in a dictionary. The kSecUseAuthenticationUI constant is the key and its
|
|
|
+ value is one of the constants defined here.
|
|
|
+ If the key kSecUseAuthenticationUI not provided then kSecUseAuthenticationUIAllow
|
|
|
+ is used as default.
|
|
|
+ */
|
|
|
+public enum AuthenticationUI {
|
|
|
+ /**
|
|
|
+ Specifies that authenticate UI can appear.
|
|
|
+ */
|
|
|
+ case allow
|
|
|
+
|
|
|
+ /**
|
|
|
+ Specifies that the error
|
|
|
+ errSecInteractionNotAllowed will be returned if an item needs
|
|
|
+ to authenticate with UI
|
|
|
+ */
|
|
|
+ case fail
|
|
|
+
|
|
|
+ /**
|
|
|
+ Specifies that all items which need
|
|
|
+ to authenticate with UI will be silently skipped. This value can be used
|
|
|
+ only with SecItemCopyMatching.
|
|
|
+ */
|
|
|
+ case skip
|
|
|
+}
|
|
|
+
|
|
|
+@available(iOS 9.0, OSX 10.11, *)
|
|
|
+extension AuthenticationUI {
|
|
|
+ public var rawValue: String {
|
|
|
+ switch self {
|
|
|
+ case .allow:
|
|
|
+ return UseAuthenticationUIAllow
|
|
|
+ case .fail:
|
|
|
+ return UseAuthenticationUIFail
|
|
|
+ case .skip:
|
|
|
+ return UseAuthenticationUISkip
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var description: String {
|
|
|
+ switch self {
|
|
|
+ case .allow:
|
|
|
+ return "allow"
|
|
|
+ case .fail:
|
|
|
+ return "fail"
|
|
|
+ case .skip:
|
|
|
+ return "skip"
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public struct AuthenticationPolicy: OptionSet {
|
|
|
+ /**
|
|
|
+ User presence policy using Touch ID or Passcode. Touch ID does not
|
|
|
+ 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, watchOS 2.0, tvOS 8.0, *)
|
|
|
+ public static let userPresence = AuthenticationPolicy(rawValue: 1 << 0)
|
|
|
+
|
|
|
+ /**
|
|
|
+ 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 11.3, OSX 10.13.4, watchOS 4.3, 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. When Face ID is re-enrolled this item is invalidated.
|
|
|
+ */
|
|
|
+ @available(iOS 11.3, OSX 10.13, watchOS 4.3, 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, watchOS 2.0, 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, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
|
|
|
+ public static let or = AuthenticationPolicy(rawValue: 1 << 14)
|
|
|
+
|
|
|
+ /**
|
|
|
+ Constraint logic operation: when using more than one constraint,
|
|
|
+ all must be satisfied.
|
|
|
+ */
|
|
|
+ @available(iOS 9.0, OSX 10.12.1, watchOS 2.0, 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, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
|
|
|
+ public static let privateKeyUsage = AuthenticationPolicy(rawValue: 1 << 30)
|
|
|
+
|
|
|
+ /**
|
|
|
+ Security: Application provided password for data encryption key generation.
|
|
|
+ This is not a constraint but additional item encryption mechanism.
|
|
|
+ */
|
|
|
+ @available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
|
|
|
+ public static let applicationPassword = AuthenticationPolicy(rawValue: 1 << 31)
|
|
|
+
|
|
|
+ #if swift(>=2.3)
|
|
|
+ public let rawValue: UInt
|
|
|
+
|
|
|
+ public init(rawValue: UInt) {
|
|
|
+ self.rawValue = rawValue
|
|
|
+ }
|
|
|
+ #else
|
|
|
+ public let rawValue: Int
|
|
|
+
|
|
|
+ public init(rawValue: Int) {
|
|
|
+ self.rawValue = rawValue
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+}
|
|
|
+
|
|
|
+public struct Attributes {
|
|
|
+ public var `class`: String? {
|
|
|
+ return attributes[Class] as? String
|
|
|
+ }
|
|
|
+ public var data: Data? {
|
|
|
+ return attributes[ValueData] as? Data
|
|
|
+ }
|
|
|
+ public var ref: Data? {
|
|
|
+ return attributes[ValueRef] as? Data
|
|
|
+ }
|
|
|
+ public var persistentRef: Data? {
|
|
|
+ return attributes[ValuePersistentRef] as? Data
|
|
|
+ }
|
|
|
+
|
|
|
+ public var accessible: String? {
|
|
|
+ return attributes[AttributeAccessible] as? String
|
|
|
+ }
|
|
|
+ public var accessControl: SecAccessControl? {
|
|
|
+ if #available(OSX 10.10, *) {
|
|
|
+ if let accessControl = attributes[AttributeAccessControl] {
|
|
|
+ return (accessControl as! SecAccessControl)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ } else {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public var accessGroup: String? {
|
|
|
+ return attributes[AttributeAccessGroup] as? String
|
|
|
+ }
|
|
|
+ public var synchronizable: Bool? {
|
|
|
+ return attributes[AttributeSynchronizable] as? Bool
|
|
|
+ }
|
|
|
+ public var creationDate: Date? {
|
|
|
+ return attributes[AttributeCreationDate] as? Date
|
|
|
+ }
|
|
|
+ public var modificationDate: Date? {
|
|
|
+ return attributes[AttributeModificationDate] as? Date
|
|
|
+ }
|
|
|
+ public var attributeDescription: String? {
|
|
|
+ return attributes[AttributeDescription] as? String
|
|
|
+ }
|
|
|
+ public var comment: String? {
|
|
|
+ return attributes[AttributeComment] as? String
|
|
|
+ }
|
|
|
+ public var creator: String? {
|
|
|
+ return attributes[AttributeCreator] as? String
|
|
|
+ }
|
|
|
+ public var type: String? {
|
|
|
+ return attributes[AttributeType] as? String
|
|
|
+ }
|
|
|
+ public var label: String? {
|
|
|
+ return attributes[AttributeLabel] as? String
|
|
|
+ }
|
|
|
+ public var isInvisible: Bool? {
|
|
|
+ return attributes[AttributeIsInvisible] as? Bool
|
|
|
+ }
|
|
|
+ public var isNegative: Bool? {
|
|
|
+ return attributes[AttributeIsNegative] as? Bool
|
|
|
+ }
|
|
|
+ public var account: String? {
|
|
|
+ return attributes[AttributeAccount] as? String
|
|
|
+ }
|
|
|
+ public var service: String? {
|
|
|
+ return attributes[AttributeService] as? String
|
|
|
+ }
|
|
|
+ public var generic: Data? {
|
|
|
+ return attributes[AttributeGeneric] as? Data
|
|
|
+ }
|
|
|
+ public var securityDomain: String? {
|
|
|
+ return attributes[AttributeSecurityDomain] as? String
|
|
|
+ }
|
|
|
+ public var server: String? {
|
|
|
+ return attributes[AttributeServer] as? String
|
|
|
+ }
|
|
|
+ public var `protocol`: String? {
|
|
|
+ return attributes[AttributeProtocol] as? String
|
|
|
+ }
|
|
|
+ public var authenticationType: String? {
|
|
|
+ return attributes[AttributeAuthenticationType] as? String
|
|
|
+ }
|
|
|
+ public var port: Int? {
|
|
|
+ return attributes[AttributePort] as? Int
|
|
|
+ }
|
|
|
+ public var path: String? {
|
|
|
+ return attributes[AttributePath] as? String
|
|
|
+ }
|
|
|
+
|
|
|
+ fileprivate let attributes: [String: Any]
|
|
|
+
|
|
|
+ init(attributes: [String: Any]) {
|
|
|
+ self.attributes = attributes
|
|
|
+ }
|
|
|
+
|
|
|
+ public subscript(key: String) -> Any? {
|
|
|
+ get {
|
|
|
+ return attributes[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public final class Keychain {
|
|
|
+ public var itemClass: ItemClass {
|
|
|
+ return options.itemClass
|
|
|
+ }
|
|
|
+
|
|
|
+ public var service: String {
|
|
|
+ return options.service
|
|
|
+ }
|
|
|
+
|
|
|
+ // This attribute (kSecAttrAccessGroup) applies to macOS keychain items only if you also set a value of true for the
|
|
|
+ // kSecUseDataProtectionKeychain key, the kSecAttrSynchronizable key, or both.
|
|
|
+ public var accessGroup: String? {
|
|
|
+ return options.accessGroup
|
|
|
+ }
|
|
|
+
|
|
|
+ public var server: URL {
|
|
|
+ return options.server
|
|
|
+ }
|
|
|
+
|
|
|
+ public var protocolType: ProtocolType {
|
|
|
+ return options.protocolType
|
|
|
+ }
|
|
|
+
|
|
|
+ public var authenticationType: AuthenticationType {
|
|
|
+ return options.authenticationType
|
|
|
+ }
|
|
|
+
|
|
|
+ public var accessibility: Accessibility {
|
|
|
+ return options.accessibility
|
|
|
+ }
|
|
|
+
|
|
|
+ @available(iOS 8.0, OSX 10.10, *)
|
|
|
+ @available(watchOS, unavailable)
|
|
|
+ public var authenticationPolicy: AuthenticationPolicy? {
|
|
|
+ return options.authenticationPolicy
|
|
|
+ }
|
|
|
+
|
|
|
+ public var synchronizable: Bool {
|
|
|
+ return options.synchronizable
|
|
|
+ }
|
|
|
+
|
|
|
+ public var label: String? {
|
|
|
+ return options.label
|
|
|
+ }
|
|
|
+
|
|
|
+ public var comment: String? {
|
|
|
+ return options.comment
|
|
|
+ }
|
|
|
+
|
|
|
+ @available(iOS 8.0, OSX 10.10, *)
|
|
|
+ @available(watchOS, unavailable)
|
|
|
+ public var authenticationPrompt: String? {
|
|
|
+ return options.authenticationPrompt
|
|
|
+ }
|
|
|
+
|
|
|
+ @available(iOS 9.0, OSX 10.11, *)
|
|
|
+ public var authenticationUI: AuthenticationUI {
|
|
|
+ return options.authenticationUI ?? .allow
|
|
|
+ }
|
|
|
+
|
|
|
+ #if os(iOS) || os(OSX)
|
|
|
+ @available(iOS 9.0, OSX 10.11, *)
|
|
|
+ public var authenticationContext: LAContext? {
|
|
|
+ return options.authenticationContext as? LAContext
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ fileprivate let options: Options
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ public convenience init() {
|
|
|
+ var options = Options()
|
|
|
+ if let bundleIdentifier = Bundle.main.bundleIdentifier {
|
|
|
+ options.service = bundleIdentifier
|
|
|
+ }
|
|
|
+ self.init(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ public convenience init(service: String) {
|
|
|
+ var options = Options()
|
|
|
+ options.service = service
|
|
|
+ self.init(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ public convenience init(accessGroup: String) {
|
|
|
+ var options = Options()
|
|
|
+ if let bundleIdentifier = Bundle.main.bundleIdentifier {
|
|
|
+ options.service = bundleIdentifier
|
|
|
+ }
|
|
|
+ options.accessGroup = accessGroup
|
|
|
+ self.init(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ public convenience init(service: String, accessGroup: String) {
|
|
|
+ var options = Options()
|
|
|
+ options.service = service
|
|
|
+ options.accessGroup = accessGroup
|
|
|
+ self.init(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ public convenience init(server: String, protocolType: ProtocolType, accessGroup: String? = nil, authenticationType: AuthenticationType = .default) {
|
|
|
+ self.init(server: URL(string: server)!, protocolType: protocolType, accessGroup: accessGroup, authenticationType: authenticationType)
|
|
|
+ }
|
|
|
+
|
|
|
+ public convenience init(server: URL, protocolType: ProtocolType, accessGroup: String? = nil, authenticationType: AuthenticationType = .default) {
|
|
|
+ var options = Options()
|
|
|
+ options.itemClass = .internetPassword
|
|
|
+ options.server = server
|
|
|
+ options.protocolType = protocolType
|
|
|
+ options.accessGroup = accessGroup
|
|
|
+ options.authenticationType = authenticationType
|
|
|
+ self.init(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ fileprivate init(_ opts: Options) {
|
|
|
+ options = opts
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ public func accessibility(_ accessibility: Accessibility) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ options.accessibility = accessibility
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ @available(iOS 8.0, OSX 10.10, *)
|
|
|
+ @available(watchOS, unavailable)
|
|
|
+ public func accessibility(_ accessibility: Accessibility, authenticationPolicy: AuthenticationPolicy) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ options.accessibility = accessibility
|
|
|
+ options.authenticationPolicy = authenticationPolicy
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func synchronizable(_ synchronizable: Bool) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ options.synchronizable = synchronizable
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func label(_ label: String) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ options.label = label
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func comment(_ comment: String) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ options.comment = comment
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func attributes(_ attributes: [String: Any]) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ attributes.forEach { options.attributes.updateValue($1, forKey: $0) }
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ @available(iOS 8.0, OSX 10.10, *)
|
|
|
+ @available(watchOS, unavailable)
|
|
|
+ public func authenticationPrompt(_ authenticationPrompt: String) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ options.authenticationPrompt = authenticationPrompt
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ @available(iOS 9.0, OSX 10.11, *)
|
|
|
+ public func authenticationUI(_ authenticationUI: AuthenticationUI) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ options.authenticationUI = authenticationUI
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+
|
|
|
+ #if os(iOS) || os(OSX)
|
|
|
+ @available(iOS 9.0, OSX 10.11, *)
|
|
|
+ public func authenticationContext(_ authenticationContext: LAContext) -> Keychain {
|
|
|
+ var options = self.options
|
|
|
+ options.authenticationContext = authenticationContext
|
|
|
+ return Keychain(options)
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ public func get(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> String? {
|
|
|
+ return try getString(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func getString(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> String? {
|
|
|
+ guard let data = try getData(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable) else {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ guard let string = String(data: data, encoding: .utf8) else {
|
|
|
+ print("failed to convert data to string")
|
|
|
+ throw Status.conversionError
|
|
|
+ }
|
|
|
+ return string
|
|
|
+ }
|
|
|
+
|
|
|
+ public func getData(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> Data? {
|
|
|
+ var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
|
|
|
+
|
|
|
+ query[MatchLimit] = MatchLimitOne
|
|
|
+ query[ReturnData] = kCFBooleanTrue
|
|
|
+
|
|
|
+ query[AttributeAccount] = key
|
|
|
+
|
|
|
+ var result: AnyObject?
|
|
|
+ let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
|
+
|
|
|
+ switch status {
|
|
|
+ case errSecSuccess:
|
|
|
+ guard let data = result as? Data else {
|
|
|
+ throw Status.unexpectedError
|
|
|
+ }
|
|
|
+ return data
|
|
|
+ case errSecItemNotFound:
|
|
|
+ return nil
|
|
|
+ default:
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func get<T>(_ key: String, ignoringAttributeSynchronizable: Bool = true, handler: (Attributes?) -> T) throws -> T {
|
|
|
+ var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
|
|
|
+
|
|
|
+ query[MatchLimit] = MatchLimitOne
|
|
|
+
|
|
|
+ query[ReturnData] = kCFBooleanTrue
|
|
|
+ query[ReturnAttributes] = kCFBooleanTrue
|
|
|
+ query[ReturnRef] = kCFBooleanTrue
|
|
|
+ query[ReturnPersistentRef] = kCFBooleanTrue
|
|
|
+
|
|
|
+ query[AttributeAccount] = key
|
|
|
+
|
|
|
+ var result: AnyObject?
|
|
|
+ let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
|
+
|
|
|
+ switch status {
|
|
|
+ case errSecSuccess:
|
|
|
+ guard let attributes = result as? [String: Any] else {
|
|
|
+ throw Status.unexpectedError
|
|
|
+ }
|
|
|
+ return handler(Attributes(attributes: attributes))
|
|
|
+ case errSecItemNotFound:
|
|
|
+ return handler(nil)
|
|
|
+ default:
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ public func set(_ value: String, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
|
|
|
+ guard let data = value.data(using: .utf8, allowLossyConversion: false) else {
|
|
|
+ print("failed to convert string to data")
|
|
|
+ throw Status.conversionError
|
|
|
+ }
|
|
|
+ try set(data, key: key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func set(_ value: Data, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
|
|
|
+ var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
|
|
|
+ query[AttributeAccount] = key
|
|
|
+ #if os(iOS)
|
|
|
+ if #available(iOS 9.0, *) {
|
|
|
+ if let authenticationUI = options.authenticationUI {
|
|
|
+ query[UseAuthenticationUI] = authenticationUI.rawValue
|
|
|
+ } else {
|
|
|
+ query[UseAuthenticationUI] = UseAuthenticationUIFail
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ query[UseNoAuthenticationUI] = kCFBooleanTrue
|
|
|
+ }
|
|
|
+ #elseif os(OSX)
|
|
|
+ query[ReturnData] = kCFBooleanTrue
|
|
|
+ if #available(OSX 10.11, *) {
|
|
|
+ if let authenticationUI = options.authenticationUI {
|
|
|
+ query[UseAuthenticationUI] = authenticationUI.rawValue
|
|
|
+ } else {
|
|
|
+ query[UseAuthenticationUI] = UseAuthenticationUIFail
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #else
|
|
|
+ if let authenticationUI = options.authenticationUI {
|
|
|
+ query[UseAuthenticationUI] = authenticationUI.rawValue
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ var status = SecItemCopyMatching(query as CFDictionary, nil)
|
|
|
+ switch status {
|
|
|
+ case errSecSuccess, errSecInteractionNotAllowed:
|
|
|
+ var query = options.query()
|
|
|
+ query[AttributeAccount] = key
|
|
|
+
|
|
|
+ var (attributes, error) = options.attributes(key: nil, value: value)
|
|
|
+ if let error = error {
|
|
|
+ print(error.localizedDescription)
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+
|
|
|
+ options.attributes.forEach { attributes.updateValue($1, forKey: $0) }
|
|
|
+
|
|
|
+ #if os(iOS)
|
|
|
+ if status == errSecInteractionNotAllowed && floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_8_0) {
|
|
|
+ try remove(key)
|
|
|
+ try set(value, key: key)
|
|
|
+ } else {
|
|
|
+ status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
|
|
|
+ if status != errSecSuccess {
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #else
|
|
|
+ status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
|
|
|
+ if status != errSecSuccess {
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ case errSecItemNotFound:
|
|
|
+ var (attributes, error) = options.attributes(key: key, value: value)
|
|
|
+ if let error = error {
|
|
|
+ print(error.localizedDescription)
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+
|
|
|
+ options.attributes.forEach { attributes.updateValue($1, forKey: $0) }
|
|
|
+
|
|
|
+ status = SecItemAdd(attributes as CFDictionary, nil)
|
|
|
+ if status != errSecSuccess {
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public subscript(key: String) -> String? {
|
|
|
+ get {
|
|
|
+ #if swift(>=5.0)
|
|
|
+ return try? get(key)
|
|
|
+ #else
|
|
|
+ return (try? get(key)).flatMap { $0 }
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
+ set {
|
|
|
+ if let value = newValue {
|
|
|
+ do {
|
|
|
+ try set(value, key: key)
|
|
|
+ } catch {}
|
|
|
+ } else {
|
|
|
+ do {
|
|
|
+ try remove(key)
|
|
|
+ } catch {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public subscript(string key: String) -> String? {
|
|
|
+ get {
|
|
|
+ return self[key]
|
|
|
+ }
|
|
|
+
|
|
|
+ set {
|
|
|
+ self[key] = newValue
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public subscript(data key: String) -> Data? {
|
|
|
+ get {
|
|
|
+ #if swift(>=5.0)
|
|
|
+ return try? getData(key)
|
|
|
+ #else
|
|
|
+ return (try? getData(key)).flatMap { $0 }
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
+ set {
|
|
|
+ if let value = newValue {
|
|
|
+ do {
|
|
|
+ try set(value, key: key)
|
|
|
+ } catch {}
|
|
|
+ } else {
|
|
|
+ do {
|
|
|
+ try remove(key)
|
|
|
+ } catch {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public subscript(attributes key: String) -> Attributes? {
|
|
|
+ get {
|
|
|
+ #if swift(>=5.0)
|
|
|
+ return try? get(key) { $0 }
|
|
|
+ #else
|
|
|
+ return (try? get(key) { $0 }).flatMap { $0 }
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ public func remove(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws {
|
|
|
+ var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
|
|
|
+ query[AttributeAccount] = key
|
|
|
+
|
|
|
+ let status = SecItemDelete(query as CFDictionary)
|
|
|
+ if status != errSecSuccess && status != errSecItemNotFound {
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func removeAll() throws {
|
|
|
+ var query = options.query()
|
|
|
+ #if !os(iOS) && !os(watchOS) && !os(tvOS)
|
|
|
+ query[MatchLimit] = MatchLimitAll
|
|
|
+ #endif
|
|
|
+
|
|
|
+ let status = SecItemDelete(query as CFDictionary)
|
|
|
+ if status != errSecSuccess && status != errSecItemNotFound {
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ 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, *) {
|
|
|
+ if let authenticationUI = options.authenticationUI {
|
|
|
+ query[UseAuthenticationUI] = authenticationUI.rawValue
|
|
|
+ } else {
|
|
|
+ query[UseAuthenticationUI] = UseAuthenticationUIFail
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ query[UseNoAuthenticationUI] = kCFBooleanTrue
|
|
|
+ }
|
|
|
+ #else
|
|
|
+ if #available(OSX 10.11, *) {
|
|
|
+ if let authenticationUI = options.authenticationUI {
|
|
|
+ query[UseAuthenticationUI] = authenticationUI.rawValue
|
|
|
+ } else {
|
|
|
+ query[UseAuthenticationUI] = UseAuthenticationUIFail
|
|
|
+ }
|
|
|
+ } else if #available(OSX 10.10, *) {
|
|
|
+ query[UseNoAuthenticationUI] = kCFBooleanTrue
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ } else {
|
|
|
+ if #available(iOS 9.0, OSX 10.11, *) {
|
|
|
+ if let authenticationUI = options.authenticationUI {
|
|
|
+ query[UseAuthenticationUI] = authenticationUI.rawValue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let status = SecItemCopyMatching(query as CFDictionary, nil)
|
|
|
+ switch status {
|
|
|
+ case errSecSuccess:
|
|
|
+ return true
|
|
|
+ case errSecInteractionNotAllowed:
|
|
|
+ if withoutAuthenticationUI {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ case errSecItemNotFound:
|
|
|
+ return false
|
|
|
+ default:
|
|
|
+ throw securityError(status: status)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ public class func allKeys(_ itemClass: ItemClass) -> [(String, String)] {
|
|
|
+ var query = [String: Any]()
|
|
|
+ query[Class] = itemClass.rawValue
|
|
|
+ query[AttributeSynchronizable] = SynchronizableAny
|
|
|
+ query[MatchLimit] = MatchLimitAll
|
|
|
+ query[ReturnAttributes] = kCFBooleanTrue
|
|
|
+
|
|
|
+ var result: AnyObject?
|
|
|
+ let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
|
+
|
|
|
+ switch status {
|
|
|
+ case errSecSuccess:
|
|
|
+ if let items = result as? [[String: Any]] {
|
|
|
+ return prettify(itemClass: itemClass, items: items).map {
|
|
|
+ switch itemClass {
|
|
|
+ case .genericPassword:
|
|
|
+ return (($0["service"] ?? "") as! String, ($0["key"] ?? "") as! String)
|
|
|
+ case .internetPassword:
|
|
|
+ return (($0["server"] ?? "") as! String, ($0["key"] ?? "") as! String)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case errSecItemNotFound:
|
|
|
+ return []
|
|
|
+ default: ()
|
|
|
+ }
|
|
|
+
|
|
|
+ securityError(status: status)
|
|
|
+ return []
|
|
|
+ }
|
|
|
+
|
|
|
+ public func allKeys() -> [String] {
|
|
|
+ let allItems = type(of: self).prettify(itemClass: itemClass, items: items())
|
|
|
+ let filter: ([String: Any]) -> String? = { $0["key"] as? String }
|
|
|
+
|
|
|
+ #if swift(>=4.1)
|
|
|
+ return allItems.compactMap(filter)
|
|
|
+ #else
|
|
|
+ return allItems.flatMap(filter)
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
+ public class func allItems(_ itemClass: ItemClass) -> [[String: Any]] {
|
|
|
+ var query = [String: Any]()
|
|
|
+ query[Class] = itemClass.rawValue
|
|
|
+ query[MatchLimit] = MatchLimitAll
|
|
|
+ query[ReturnAttributes] = kCFBooleanTrue
|
|
|
+ #if os(iOS) || os(watchOS) || os(tvOS)
|
|
|
+ query[ReturnData] = kCFBooleanTrue
|
|
|
+ #endif
|
|
|
+
|
|
|
+ var result: AnyObject?
|
|
|
+ let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
|
+
|
|
|
+ switch status {
|
|
|
+ case errSecSuccess:
|
|
|
+ if let items = result as? [[String: Any]] {
|
|
|
+ return prettify(itemClass: itemClass, items: items)
|
|
|
+ }
|
|
|
+ case errSecItemNotFound:
|
|
|
+ return []
|
|
|
+ default: ()
|
|
|
+ }
|
|
|
+
|
|
|
+ securityError(status: status)
|
|
|
+ return []
|
|
|
+ }
|
|
|
+
|
|
|
+ public func allItems() -> [[String: Any]] {
|
|
|
+ return type(of: self).prettify(itemClass: itemClass, items: items())
|
|
|
+ }
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ public func getSharedPassword(_ completion: @escaping (_ account: String?, _ password: String?, _ error: Error?) -> () = { account, password, error -> () in }) {
|
|
|
+ if let domain = server.host {
|
|
|
+ type(of: self).requestSharedWebCredential(domain: domain, account: nil) { (credentials, error) -> () in
|
|
|
+ if let credential = credentials.first {
|
|
|
+ let account = credential["account"]
|
|
|
+ let password = credential["password"]
|
|
|
+ completion(account, password, error)
|
|
|
+ } else {
|
|
|
+ completion(nil, nil, error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ let error = securityError(status: Status.param.rawValue)
|
|
|
+ completion(nil, nil, error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ public func getSharedPassword(_ account: String, completion: @escaping (_ password: String?, _ error: Error?) -> () = { password, error -> () in }) {
|
|
|
+ if let domain = server.host {
|
|
|
+ type(of: self).requestSharedWebCredential(domain: domain, account: account) { (credentials, error) -> () in
|
|
|
+ if let credential = credentials.first {
|
|
|
+ if let password = credential["password"] {
|
|
|
+ completion(password, error)
|
|
|
+ } else {
|
|
|
+ completion(nil, error)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ completion(nil, error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ let error = securityError(status: Status.param.rawValue)
|
|
|
+ completion(nil, error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ public func setSharedPassword(_ password: String, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
|
|
|
+ setSharedPassword(password as String?, account: account, completion: completion)
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ fileprivate func setSharedPassword(_ password: String?, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
|
|
|
+ if let domain = server.host {
|
|
|
+ SecAddSharedWebCredential(domain as CFString, account as CFString, password as CFString?) { error -> () in
|
|
|
+ if let error = error {
|
|
|
+ completion(error.error)
|
|
|
+ } else {
|
|
|
+ completion(nil)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ let error = securityError(status: Status.param.rawValue)
|
|
|
+ completion(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ public func removeSharedPassword(_ account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
|
|
|
+ setSharedPassword(nil, account: account, completion: completion)
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ public class func requestSharedWebCredential(_ completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
|
|
|
+ requestSharedWebCredential(domain: nil, account: nil, completion: completion)
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ public class func requestSharedWebCredential(domain: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
|
|
|
+ requestSharedWebCredential(domain: domain, account: nil, completion: completion)
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ public class func requestSharedWebCredential(domain: String, account: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
|
|
|
+ requestSharedWebCredential(domain: Optional(domain), account: Optional(account)!, completion: completion)
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ fileprivate class func requestSharedWebCredential(domain: String?, account: String?, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> ()) {
|
|
|
+ SecRequestSharedWebCredential(domain as CFString?, account as CFString?) { (credentials, error) -> () in
|
|
|
+ var remoteError: NSError?
|
|
|
+ if let error = error {
|
|
|
+ remoteError = error.error
|
|
|
+ if remoteError?.code != Int(errSecItemNotFound) {
|
|
|
+ print("error:[\(remoteError!.code)] \(remoteError!.localizedDescription)")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if let credentials = credentials {
|
|
|
+ let credentials = (credentials as NSArray).map { credentials -> [String: String] in
|
|
|
+ var credential = [String: String]()
|
|
|
+ if let credentials = credentials as? [String: String] {
|
|
|
+ if let server = credentials[AttributeServer] {
|
|
|
+ credential["server"] = server
|
|
|
+ }
|
|
|
+ if let account = credentials[AttributeAccount] {
|
|
|
+ credential["account"] = account
|
|
|
+ }
|
|
|
+ if let password = credentials[SharedPassword] {
|
|
|
+ credential["password"] = password
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return credential
|
|
|
+ }
|
|
|
+ completion(credentials, remoteError)
|
|
|
+ } else {
|
|
|
+ completion([], remoteError)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+ /**
|
|
|
+ @abstract Returns a randomly generated password.
|
|
|
+ @return String password in the form xxx-xxx-xxx-xxx where x is taken from the sets "abcdefghkmnopqrstuvwxy", "ABCDEFGHJKLMNPQRSTUVWXYZ", "3456789" with at least one character from each set being present.
|
|
|
+ */
|
|
|
+ @available(iOS 8.0, *)
|
|
|
+ public class func generatePassword() -> String {
|
|
|
+ return SecCreateSharedWebCredentialPassword()! as String
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ fileprivate func items() -> [[String: Any]] {
|
|
|
+ var query = options.query()
|
|
|
+ query[MatchLimit] = MatchLimitAll
|
|
|
+ query[ReturnAttributes] = kCFBooleanTrue
|
|
|
+ #if os(iOS) || os(watchOS) || os(tvOS)
|
|
|
+ query[ReturnData] = kCFBooleanTrue
|
|
|
+ #endif
|
|
|
+
|
|
|
+ var result: AnyObject?
|
|
|
+ let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
|
+
|
|
|
+ switch status {
|
|
|
+ case errSecSuccess:
|
|
|
+ if let items = result as? [[String: Any]] {
|
|
|
+ return items
|
|
|
+ }
|
|
|
+ case errSecItemNotFound:
|
|
|
+ return []
|
|
|
+ default: ()
|
|
|
+ }
|
|
|
+
|
|
|
+ securityError(status: status)
|
|
|
+ return []
|
|
|
+ }
|
|
|
+
|
|
|
+ fileprivate class func prettify(itemClass: ItemClass, items: [[String: Any]]) -> [[String: Any]] {
|
|
|
+ let items = items.map { attributes -> [String: Any] in
|
|
|
+ var item = [String: Any]()
|
|
|
+
|
|
|
+ item["class"] = itemClass.description
|
|
|
+
|
|
|
+ if let accessGroup = attributes[AttributeAccessGroup] as? String {
|
|
|
+ item["accessGroup"] = accessGroup
|
|
|
+ }
|
|
|
+
|
|
|
+ switch itemClass {
|
|
|
+ case .genericPassword:
|
|
|
+ if let service = attributes[AttributeService] as? String {
|
|
|
+ item["service"] = service
|
|
|
+ }
|
|
|
+ case .internetPassword:
|
|
|
+ if let server = attributes[AttributeServer] as? String {
|
|
|
+ item["server"] = server
|
|
|
+ }
|
|
|
+ if let proto = attributes[AttributeProtocol] as? String {
|
|
|
+ if let protocolType = ProtocolType(rawValue: proto) {
|
|
|
+ item["protocol"] = protocolType.description
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if let auth = attributes[AttributeAuthenticationType] as? String {
|
|
|
+ if let authenticationType = AuthenticationType(rawValue: auth) {
|
|
|
+ item["authenticationType"] = authenticationType.description
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if let key = attributes[AttributeAccount] as? String {
|
|
|
+ item["key"] = key
|
|
|
+ }
|
|
|
+ if let data = attributes[ValueData] as? Data {
|
|
|
+ if let text = String(data: data, encoding: .utf8) {
|
|
|
+ item["value"] = text
|
|
|
+ } else {
|
|
|
+ item["value"] = data
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if let accessible = attributes[AttributeAccessible] as? String {
|
|
|
+ if let accessibility = Accessibility(rawValue: accessible) {
|
|
|
+ item["accessibility"] = accessibility.description
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if let synchronizable = attributes[AttributeSynchronizable] as? Bool {
|
|
|
+ item["synchronizable"] = synchronizable ? "true" : "false"
|
|
|
+ }
|
|
|
+
|
|
|
+ return item
|
|
|
+ }
|
|
|
+ return items
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK:
|
|
|
+
|
|
|
+ @discardableResult
|
|
|
+ fileprivate class func securityError(status: OSStatus) -> Error {
|
|
|
+ let error = Status(status: status)
|
|
|
+ if error != .userCanceled {
|
|
|
+ print("OSStatus error:[\(error.errorCode)] \(error.description)")
|
|
|
+ }
|
|
|
+
|
|
|
+ return error
|
|
|
+ }
|
|
|
+
|
|
|
+ @discardableResult
|
|
|
+ fileprivate func securityError(status: OSStatus) -> Error {
|
|
|
+ return type(of: self).securityError(status: status)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+struct Options {
|
|
|
+ var itemClass: ItemClass = .genericPassword
|
|
|
+
|
|
|
+ var service: String = ""
|
|
|
+ var accessGroup: String? = nil
|
|
|
+
|
|
|
+ var server: URL!
|
|
|
+ var protocolType: ProtocolType!
|
|
|
+ var authenticationType: AuthenticationType = .default
|
|
|
+
|
|
|
+ var accessibility: Accessibility = .afterFirstUnlock
|
|
|
+ var authenticationPolicy: AuthenticationPolicy?
|
|
|
+
|
|
|
+ var synchronizable: Bool = false
|
|
|
+
|
|
|
+ var label: String?
|
|
|
+ var comment: String?
|
|
|
+
|
|
|
+ var authenticationPrompt: String?
|
|
|
+ var authenticationUI: AuthenticationUI?
|
|
|
+ var authenticationContext: AnyObject?
|
|
|
+
|
|
|
+ var attributes = [String: Any]()
|
|
|
+}
|
|
|
+
|
|
|
+/** Class Key Constant */
|
|
|
+private let Class = String(kSecClass)
|
|
|
+
|
|
|
+/** Attribute Key Constants */
|
|
|
+private let AttributeAccessible = String(kSecAttrAccessible)
|
|
|
+
|
|
|
+@available(iOS 8.0, OSX 10.10, *)
|
|
|
+private let AttributeAccessControl = String(kSecAttrAccessControl)
|
|
|
+
|
|
|
+private let AttributeAccessGroup = String(kSecAttrAccessGroup)
|
|
|
+private let AttributeSynchronizable = String(kSecAttrSynchronizable)
|
|
|
+private let AttributeCreationDate = String(kSecAttrCreationDate)
|
|
|
+private let AttributeModificationDate = String(kSecAttrModificationDate)
|
|
|
+private let AttributeDescription = String(kSecAttrDescription)
|
|
|
+private let AttributeComment = String(kSecAttrComment)
|
|
|
+private let AttributeCreator = String(kSecAttrCreator)
|
|
|
+private let AttributeType = String(kSecAttrType)
|
|
|
+private let AttributeLabel = String(kSecAttrLabel)
|
|
|
+private let AttributeIsInvisible = String(kSecAttrIsInvisible)
|
|
|
+private let AttributeIsNegative = String(kSecAttrIsNegative)
|
|
|
+private let AttributeAccount = String(kSecAttrAccount)
|
|
|
+private let AttributeService = String(kSecAttrService)
|
|
|
+private let AttributeGeneric = String(kSecAttrGeneric)
|
|
|
+private let AttributeSecurityDomain = String(kSecAttrSecurityDomain)
|
|
|
+private let AttributeServer = String(kSecAttrServer)
|
|
|
+private let AttributeProtocol = String(kSecAttrProtocol)
|
|
|
+private let AttributeAuthenticationType = String(kSecAttrAuthenticationType)
|
|
|
+private let AttributePort = String(kSecAttrPort)
|
|
|
+private let AttributePath = String(kSecAttrPath)
|
|
|
+
|
|
|
+private let SynchronizableAny = kSecAttrSynchronizableAny
|
|
|
+
|
|
|
+/** Search Constants */
|
|
|
+private let MatchLimit = String(kSecMatchLimit)
|
|
|
+private let MatchLimitOne = kSecMatchLimitOne
|
|
|
+private let MatchLimitAll = kSecMatchLimitAll
|
|
|
+
|
|
|
+/** Return Type Key Constants */
|
|
|
+private let ReturnData = String(kSecReturnData)
|
|
|
+private let ReturnAttributes = String(kSecReturnAttributes)
|
|
|
+private let ReturnRef = String(kSecReturnRef)
|
|
|
+private let ReturnPersistentRef = String(kSecReturnPersistentRef)
|
|
|
+
|
|
|
+/** Value Type Key Constants */
|
|
|
+private let ValueData = String(kSecValueData)
|
|
|
+private let ValueRef = String(kSecValueRef)
|
|
|
+private let ValuePersistentRef = String(kSecValuePersistentRef)
|
|
|
+
|
|
|
+/** Other Constants */
|
|
|
+@available(iOS 8.0, OSX 10.10, tvOS 8.0, *)
|
|
|
+private let UseOperationPrompt = String(kSecUseOperationPrompt)
|
|
|
+
|
|
|
+@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)
|
|
|
+
|
|
|
+@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, watchOS 2.0, tvOS 9.0, *)
|
|
|
+private let UseAuthenticationContext = String(kSecUseAuthenticationContext)
|
|
|
+
|
|
|
+@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, watchOS 2.0, tvOS 9.0, *)
|
|
|
+private let UseAuthenticationUIFail = String(kSecUseAuthenticationUIFail)
|
|
|
+
|
|
|
+@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
|
|
|
+private let UseAuthenticationUISkip = String(kSecUseAuthenticationUISkip)
|
|
|
+
|
|
|
+#if os(iOS) && !targetEnvironment(macCatalyst)
|
|
|
+/** Credential Key Constants */
|
|
|
+private let SharedPassword = String(kSecSharedPassword)
|
|
|
+#endif
|
|
|
+
|
|
|
+extension Keychain: CustomStringConvertible, CustomDebugStringConvertible {
|
|
|
+ public var description: String {
|
|
|
+ let items = allItems()
|
|
|
+ if items.isEmpty {
|
|
|
+ return "[]"
|
|
|
+ }
|
|
|
+ var description = "[\n"
|
|
|
+ for item in items {
|
|
|
+ description += " "
|
|
|
+ description += "\(item)\n"
|
|
|
+ }
|
|
|
+ description += "]"
|
|
|
+ return description
|
|
|
+ }
|
|
|
+
|
|
|
+ public var debugDescription: String {
|
|
|
+ return "\(items())"
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension Options {
|
|
|
+ func query(ignoringAttributeSynchronizable: Bool = true) -> [String: Any] {
|
|
|
+ var query = [String: Any]()
|
|
|
+
|
|
|
+ query[Class] = itemClass.rawValue
|
|
|
+ if let accessGroup = self.accessGroup {
|
|
|
+ query[AttributeAccessGroup] = accessGroup
|
|
|
+ }
|
|
|
+ if ignoringAttributeSynchronizable {
|
|
|
+ query[AttributeSynchronizable] = SynchronizableAny
|
|
|
+ } else {
|
|
|
+ query[AttributeSynchronizable] = synchronizable ? kCFBooleanTrue : kCFBooleanFalse
|
|
|
+ }
|
|
|
+
|
|
|
+ switch itemClass {
|
|
|
+ case .genericPassword:
|
|
|
+ query[AttributeService] = service
|
|
|
+ case .internetPassword:
|
|
|
+ query[AttributeServer] = server.host
|
|
|
+ query[AttributePort] = server.port
|
|
|
+ query[AttributeProtocol] = protocolType.rawValue
|
|
|
+ query[AttributeAuthenticationType] = authenticationType.rawValue
|
|
|
+ }
|
|
|
+
|
|
|
+ if #available(OSX 10.10, *) {
|
|
|
+ if authenticationPrompt != nil {
|
|
|
+ query[UseOperationPrompt] = authenticationPrompt
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #if !os(watchOS)
|
|
|
+ if #available(iOS 9.0, OSX 10.11, *) {
|
|
|
+ if authenticationContext != nil {
|
|
|
+ query[UseAuthenticationContext] = authenticationContext
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ return query
|
|
|
+ }
|
|
|
+
|
|
|
+ func attributes(key: String?, value: Data) -> ([String: Any], Error?) {
|
|
|
+ var attributes: [String: Any]
|
|
|
+
|
|
|
+ if key != nil {
|
|
|
+ attributes = query()
|
|
|
+ attributes[AttributeAccount] = key
|
|
|
+ } else {
|
|
|
+ attributes = [String: Any]()
|
|
|
+ }
|
|
|
+
|
|
|
+ attributes[ValueData] = value
|
|
|
+
|
|
|
+ if label != nil {
|
|
|
+ attributes[AttributeLabel] = label
|
|
|
+ }
|
|
|
+ if comment != nil {
|
|
|
+ attributes[AttributeComment] = comment
|
|
|
+ }
|
|
|
+
|
|
|
+ if let policy = authenticationPolicy {
|
|
|
+ if #available(OSX 10.10, *) {
|
|
|
+ var error: Unmanaged<CFError>?
|
|
|
+ guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, SecAccessControlCreateFlags(rawValue: CFOptionFlags(policy.rawValue)), &error) else {
|
|
|
+ if let error = error?.takeUnretainedValue() {
|
|
|
+ return (attributes, error.error)
|
|
|
+ }
|
|
|
+
|
|
|
+ return (attributes, Status.unexpectedError)
|
|
|
+ }
|
|
|
+ attributes[AttributeAccessControl] = accessControl
|
|
|
+ } else {
|
|
|
+ print("Unavailable 'Touch ID integration' on OS X versions prior to 10.10.")
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ attributes[AttributeAccessible] = accessibility.rawValue
|
|
|
+ }
|
|
|
+
|
|
|
+ attributes[AttributeSynchronizable] = synchronizable ? kCFBooleanTrue : kCFBooleanFalse
|
|
|
+
|
|
|
+ return (attributes, nil)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// MARK:
|
|
|
+
|
|
|
+extension Attributes: CustomStringConvertible, CustomDebugStringConvertible {
|
|
|
+ public var description: String {
|
|
|
+ return "\(attributes)"
|
|
|
+ }
|
|
|
+
|
|
|
+ public var debugDescription: String {
|
|
|
+ return description
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension ItemClass: RawRepresentable, CustomStringConvertible {
|
|
|
+ public init?(rawValue: String) {
|
|
|
+ switch rawValue {
|
|
|
+ case String(kSecClassGenericPassword):
|
|
|
+ self = .genericPassword
|
|
|
+ case String(kSecClassInternetPassword):
|
|
|
+ self = .internetPassword
|
|
|
+ default:
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var rawValue: String {
|
|
|
+ switch self {
|
|
|
+ case .genericPassword:
|
|
|
+ return String(kSecClassGenericPassword)
|
|
|
+ case .internetPassword:
|
|
|
+ return String(kSecClassInternetPassword)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var description: String {
|
|
|
+ switch self {
|
|
|
+ case .genericPassword:
|
|
|
+ return "GenericPassword"
|
|
|
+ case .internetPassword:
|
|
|
+ return "InternetPassword"
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension ProtocolType: RawRepresentable, CustomStringConvertible {
|
|
|
+ public init?(rawValue: String) {
|
|
|
+ switch rawValue {
|
|
|
+ case String(kSecAttrProtocolFTP):
|
|
|
+ self = .ftp
|
|
|
+ case String(kSecAttrProtocolFTPAccount):
|
|
|
+ self = .ftpAccount
|
|
|
+ case String(kSecAttrProtocolHTTP):
|
|
|
+ self = .http
|
|
|
+ case String(kSecAttrProtocolIRC):
|
|
|
+ self = .irc
|
|
|
+ case String(kSecAttrProtocolNNTP):
|
|
|
+ self = .nntp
|
|
|
+ case String(kSecAttrProtocolPOP3):
|
|
|
+ self = .pop3
|
|
|
+ case String(kSecAttrProtocolSMTP):
|
|
|
+ self = .smtp
|
|
|
+ case String(kSecAttrProtocolSOCKS):
|
|
|
+ self = .socks
|
|
|
+ case String(kSecAttrProtocolIMAP):
|
|
|
+ self = .imap
|
|
|
+ case String(kSecAttrProtocolLDAP):
|
|
|
+ self = .ldap
|
|
|
+ case String(kSecAttrProtocolAppleTalk):
|
|
|
+ self = .appleTalk
|
|
|
+ case String(kSecAttrProtocolAFP):
|
|
|
+ self = .afp
|
|
|
+ case String(kSecAttrProtocolTelnet):
|
|
|
+ self = .telnet
|
|
|
+ case String(kSecAttrProtocolSSH):
|
|
|
+ self = .ssh
|
|
|
+ case String(kSecAttrProtocolFTPS):
|
|
|
+ self = .ftps
|
|
|
+ case String(kSecAttrProtocolHTTPS):
|
|
|
+ self = .https
|
|
|
+ case String(kSecAttrProtocolHTTPProxy):
|
|
|
+ self = .httpProxy
|
|
|
+ case String(kSecAttrProtocolHTTPSProxy):
|
|
|
+ self = .httpsProxy
|
|
|
+ case String(kSecAttrProtocolFTPProxy):
|
|
|
+ self = .ftpProxy
|
|
|
+ case String(kSecAttrProtocolSMB):
|
|
|
+ self = .smb
|
|
|
+ case String(kSecAttrProtocolRTSP):
|
|
|
+ self = .rtsp
|
|
|
+ case String(kSecAttrProtocolRTSPProxy):
|
|
|
+ self = .rtspProxy
|
|
|
+ case String(kSecAttrProtocolDAAP):
|
|
|
+ self = .daap
|
|
|
+ case String(kSecAttrProtocolEPPC):
|
|
|
+ self = .eppc
|
|
|
+ case String(kSecAttrProtocolIPP):
|
|
|
+ self = .ipp
|
|
|
+ case String(kSecAttrProtocolNNTPS):
|
|
|
+ self = .nntps
|
|
|
+ case String(kSecAttrProtocolLDAPS):
|
|
|
+ self = .ldaps
|
|
|
+ case String(kSecAttrProtocolTelnetS):
|
|
|
+ self = .telnetS
|
|
|
+ case String(kSecAttrProtocolIMAPS):
|
|
|
+ self = .imaps
|
|
|
+ case String(kSecAttrProtocolIRCS):
|
|
|
+ self = .ircs
|
|
|
+ case String(kSecAttrProtocolPOP3S):
|
|
|
+ self = .pop3S
|
|
|
+ default:
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var rawValue: String {
|
|
|
+ switch self {
|
|
|
+ case .ftp:
|
|
|
+ return String(kSecAttrProtocolFTP)
|
|
|
+ case .ftpAccount:
|
|
|
+ return String(kSecAttrProtocolFTPAccount)
|
|
|
+ case .http:
|
|
|
+ return String(kSecAttrProtocolHTTP)
|
|
|
+ case .irc:
|
|
|
+ return String(kSecAttrProtocolIRC)
|
|
|
+ case .nntp:
|
|
|
+ return String(kSecAttrProtocolNNTP)
|
|
|
+ case .pop3:
|
|
|
+ return String(kSecAttrProtocolPOP3)
|
|
|
+ case .smtp:
|
|
|
+ return String(kSecAttrProtocolSMTP)
|
|
|
+ case .socks:
|
|
|
+ return String(kSecAttrProtocolSOCKS)
|
|
|
+ case .imap:
|
|
|
+ return String(kSecAttrProtocolIMAP)
|
|
|
+ case .ldap:
|
|
|
+ return String(kSecAttrProtocolLDAP)
|
|
|
+ case .appleTalk:
|
|
|
+ return String(kSecAttrProtocolAppleTalk)
|
|
|
+ case .afp:
|
|
|
+ return String(kSecAttrProtocolAFP)
|
|
|
+ case .telnet:
|
|
|
+ return String(kSecAttrProtocolTelnet)
|
|
|
+ case .ssh:
|
|
|
+ return String(kSecAttrProtocolSSH)
|
|
|
+ case .ftps:
|
|
|
+ return String(kSecAttrProtocolFTPS)
|
|
|
+ case .https:
|
|
|
+ return String(kSecAttrProtocolHTTPS)
|
|
|
+ case .httpProxy:
|
|
|
+ return String(kSecAttrProtocolHTTPProxy)
|
|
|
+ case .httpsProxy:
|
|
|
+ return String(kSecAttrProtocolHTTPSProxy)
|
|
|
+ case .ftpProxy:
|
|
|
+ return String(kSecAttrProtocolFTPProxy)
|
|
|
+ case .smb:
|
|
|
+ return String(kSecAttrProtocolSMB)
|
|
|
+ case .rtsp:
|
|
|
+ return String(kSecAttrProtocolRTSP)
|
|
|
+ case .rtspProxy:
|
|
|
+ return String(kSecAttrProtocolRTSPProxy)
|
|
|
+ case .daap:
|
|
|
+ return String(kSecAttrProtocolDAAP)
|
|
|
+ case .eppc:
|
|
|
+ return String(kSecAttrProtocolEPPC)
|
|
|
+ case .ipp:
|
|
|
+ return String(kSecAttrProtocolIPP)
|
|
|
+ case .nntps:
|
|
|
+ return String(kSecAttrProtocolNNTPS)
|
|
|
+ case .ldaps:
|
|
|
+ return String(kSecAttrProtocolLDAPS)
|
|
|
+ case .telnetS:
|
|
|
+ return String(kSecAttrProtocolTelnetS)
|
|
|
+ case .imaps:
|
|
|
+ return String(kSecAttrProtocolIMAPS)
|
|
|
+ case .ircs:
|
|
|
+ return String(kSecAttrProtocolIRCS)
|
|
|
+ case .pop3S:
|
|
|
+ return String(kSecAttrProtocolPOP3S)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var description: String {
|
|
|
+ switch self {
|
|
|
+ case .ftp:
|
|
|
+ return "FTP"
|
|
|
+ case .ftpAccount:
|
|
|
+ return "FTPAccount"
|
|
|
+ case .http:
|
|
|
+ return "HTTP"
|
|
|
+ case .irc:
|
|
|
+ return "IRC"
|
|
|
+ case .nntp:
|
|
|
+ return "NNTP"
|
|
|
+ case .pop3:
|
|
|
+ return "POP3"
|
|
|
+ case .smtp:
|
|
|
+ return "SMTP"
|
|
|
+ case .socks:
|
|
|
+ return "SOCKS"
|
|
|
+ case .imap:
|
|
|
+ return "IMAP"
|
|
|
+ case .ldap:
|
|
|
+ return "LDAP"
|
|
|
+ case .appleTalk:
|
|
|
+ return "AppleTalk"
|
|
|
+ case .afp:
|
|
|
+ return "AFP"
|
|
|
+ case .telnet:
|
|
|
+ return "Telnet"
|
|
|
+ case .ssh:
|
|
|
+ return "SSH"
|
|
|
+ case .ftps:
|
|
|
+ return "FTPS"
|
|
|
+ case .https:
|
|
|
+ return "HTTPS"
|
|
|
+ case .httpProxy:
|
|
|
+ return "HTTPProxy"
|
|
|
+ case .httpsProxy:
|
|
|
+ return "HTTPSProxy"
|
|
|
+ case .ftpProxy:
|
|
|
+ return "FTPProxy"
|
|
|
+ case .smb:
|
|
|
+ return "SMB"
|
|
|
+ case .rtsp:
|
|
|
+ return "RTSP"
|
|
|
+ case .rtspProxy:
|
|
|
+ return "RTSPProxy"
|
|
|
+ case .daap:
|
|
|
+ return "DAAP"
|
|
|
+ case .eppc:
|
|
|
+ return "EPPC"
|
|
|
+ case .ipp:
|
|
|
+ return "IPP"
|
|
|
+ case .nntps:
|
|
|
+ return "NNTPS"
|
|
|
+ case .ldaps:
|
|
|
+ return "LDAPS"
|
|
|
+ case .telnetS:
|
|
|
+ return "TelnetS"
|
|
|
+ case .imaps:
|
|
|
+ return "IMAPS"
|
|
|
+ case .ircs:
|
|
|
+ return "IRCS"
|
|
|
+ case .pop3S:
|
|
|
+ return "POP3S"
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension AuthenticationType: RawRepresentable, CustomStringConvertible {
|
|
|
+ public init?(rawValue: String) {
|
|
|
+ switch rawValue {
|
|
|
+ case String(kSecAttrAuthenticationTypeNTLM):
|
|
|
+ self = .ntlm
|
|
|
+ case String(kSecAttrAuthenticationTypeMSN):
|
|
|
+ self = .msn
|
|
|
+ case String(kSecAttrAuthenticationTypeDPA):
|
|
|
+ self = .dpa
|
|
|
+ case String(kSecAttrAuthenticationTypeRPA):
|
|
|
+ self = .rpa
|
|
|
+ case String(kSecAttrAuthenticationTypeHTTPBasic):
|
|
|
+ self = .httpBasic
|
|
|
+ case String(kSecAttrAuthenticationTypeHTTPDigest):
|
|
|
+ self = .httpDigest
|
|
|
+ case String(kSecAttrAuthenticationTypeHTMLForm):
|
|
|
+ self = .htmlForm
|
|
|
+ case String(kSecAttrAuthenticationTypeDefault):
|
|
|
+ self = .`default`
|
|
|
+ default:
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var rawValue: String {
|
|
|
+ switch self {
|
|
|
+ case .ntlm:
|
|
|
+ return String(kSecAttrAuthenticationTypeNTLM)
|
|
|
+ case .msn:
|
|
|
+ return String(kSecAttrAuthenticationTypeMSN)
|
|
|
+ case .dpa:
|
|
|
+ return String(kSecAttrAuthenticationTypeDPA)
|
|
|
+ case .rpa:
|
|
|
+ return String(kSecAttrAuthenticationTypeRPA)
|
|
|
+ case .httpBasic:
|
|
|
+ return String(kSecAttrAuthenticationTypeHTTPBasic)
|
|
|
+ case .httpDigest:
|
|
|
+ return String(kSecAttrAuthenticationTypeHTTPDigest)
|
|
|
+ case .htmlForm:
|
|
|
+ return String(kSecAttrAuthenticationTypeHTMLForm)
|
|
|
+ case .`default`:
|
|
|
+ return String(kSecAttrAuthenticationTypeDefault)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var description: String {
|
|
|
+ switch self {
|
|
|
+ case .ntlm:
|
|
|
+ return "NTLM"
|
|
|
+ case .msn:
|
|
|
+ return "MSN"
|
|
|
+ case .dpa:
|
|
|
+ return "DPA"
|
|
|
+ case .rpa:
|
|
|
+ return "RPA"
|
|
|
+ case .httpBasic:
|
|
|
+ return "HTTPBasic"
|
|
|
+ case .httpDigest:
|
|
|
+ return "HTTPDigest"
|
|
|
+ case .htmlForm:
|
|
|
+ return "HTMLForm"
|
|
|
+ case .`default`:
|
|
|
+ return "Default"
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension Accessibility: RawRepresentable, CustomStringConvertible {
|
|
|
+ public init?(rawValue: String) {
|
|
|
+ if #available(OSX 10.10, *) {
|
|
|
+ switch rawValue {
|
|
|
+ case String(kSecAttrAccessibleWhenUnlocked):
|
|
|
+ self = .whenUnlocked
|
|
|
+ case String(kSecAttrAccessibleAfterFirstUnlock):
|
|
|
+ self = .afterFirstUnlock
|
|
|
+ #if !targetEnvironment(macCatalyst)
|
|
|
+ case String(kSecAttrAccessibleAlways):
|
|
|
+ self = .always
|
|
|
+ #endif
|
|
|
+ case String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly):
|
|
|
+ self = .whenPasscodeSetThisDeviceOnly
|
|
|
+ case String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly):
|
|
|
+ self = .whenUnlockedThisDeviceOnly
|
|
|
+ case String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly):
|
|
|
+ self = .afterFirstUnlockThisDeviceOnly
|
|
|
+ #if !targetEnvironment(macCatalyst)
|
|
|
+ case String(kSecAttrAccessibleAlwaysThisDeviceOnly):
|
|
|
+ self = .alwaysThisDeviceOnly
|
|
|
+ #endif
|
|
|
+ default:
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ switch rawValue {
|
|
|
+ case String(kSecAttrAccessibleWhenUnlocked):
|
|
|
+ self = .whenUnlocked
|
|
|
+ case String(kSecAttrAccessibleAfterFirstUnlock):
|
|
|
+ self = .afterFirstUnlock
|
|
|
+ #if !targetEnvironment(macCatalyst)
|
|
|
+ case String(kSecAttrAccessibleAlways):
|
|
|
+ self = .always
|
|
|
+ #endif
|
|
|
+ case String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly):
|
|
|
+ self = .whenUnlockedThisDeviceOnly
|
|
|
+ case String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly):
|
|
|
+ self = .afterFirstUnlockThisDeviceOnly
|
|
|
+ #if !targetEnvironment(macCatalyst)
|
|
|
+ case String(kSecAttrAccessibleAlwaysThisDeviceOnly):
|
|
|
+ self = .alwaysThisDeviceOnly
|
|
|
+ #endif
|
|
|
+ default:
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var rawValue: String {
|
|
|
+ switch self {
|
|
|
+ case .whenUnlocked:
|
|
|
+ return String(kSecAttrAccessibleWhenUnlocked)
|
|
|
+ case .afterFirstUnlock:
|
|
|
+ return String(kSecAttrAccessibleAfterFirstUnlock)
|
|
|
+ #if !targetEnvironment(macCatalyst)
|
|
|
+ case .always:
|
|
|
+ return String(kSecAttrAccessibleAlways)
|
|
|
+ #endif
|
|
|
+ case .whenPasscodeSetThisDeviceOnly:
|
|
|
+ if #available(OSX 10.10, *) {
|
|
|
+ return String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)
|
|
|
+ } else {
|
|
|
+ fatalError("'Accessibility.WhenPasscodeSetThisDeviceOnly' is not available on this version of OS.")
|
|
|
+ }
|
|
|
+ case .whenUnlockedThisDeviceOnly:
|
|
|
+ return String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly)
|
|
|
+ case .afterFirstUnlockThisDeviceOnly:
|
|
|
+ return String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
|
|
|
+ #if !targetEnvironment(macCatalyst)
|
|
|
+ case .alwaysThisDeviceOnly:
|
|
|
+ return String(kSecAttrAccessibleAlwaysThisDeviceOnly)
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var description: String {
|
|
|
+ switch self {
|
|
|
+ case .whenUnlocked:
|
|
|
+ return "WhenUnlocked"
|
|
|
+ case .afterFirstUnlock:
|
|
|
+ return "AfterFirstUnlock"
|
|
|
+ #if !targetEnvironment(macCatalyst)
|
|
|
+ case .always:
|
|
|
+ return "Always"
|
|
|
+ #endif
|
|
|
+ case .whenPasscodeSetThisDeviceOnly:
|
|
|
+ return "WhenPasscodeSetThisDeviceOnly"
|
|
|
+ case .whenUnlockedThisDeviceOnly:
|
|
|
+ return "WhenUnlockedThisDeviceOnly"
|
|
|
+ case .afterFirstUnlockThisDeviceOnly:
|
|
|
+ return "AfterFirstUnlockThisDeviceOnly"
|
|
|
+ #if !targetEnvironment(macCatalyst)
|
|
|
+ case .alwaysThisDeviceOnly:
|
|
|
+ return "AlwaysThisDeviceOnly"
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension CFError {
|
|
|
+ var error: NSError {
|
|
|
+ let domain = CFErrorGetDomain(self) as String
|
|
|
+ let code = CFErrorGetCode(self)
|
|
|
+ let userInfo = CFErrorCopyUserInfo(self) as! [String: Any]
|
|
|
+
|
|
|
+ return NSError(domain: domain, code: code, userInfo: userInfo)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public enum Status: OSStatus, Error {
|
|
|
+ case success = 0
|
|
|
+ case unimplemented = -4
|
|
|
+ case diskFull = -34
|
|
|
+ case io = -36
|
|
|
+ case opWr = -49
|
|
|
+ case param = -50
|
|
|
+ case wrPerm = -61
|
|
|
+ case allocate = -108
|
|
|
+ case userCanceled = -128
|
|
|
+ case badReq = -909
|
|
|
+ case internalComponent = -2070
|
|
|
+ case notAvailable = -25291
|
|
|
+ case readOnly = -25292
|
|
|
+ case authFailed = -25293
|
|
|
+ case noSuchKeychain = -25294
|
|
|
+ case invalidKeychain = -25295
|
|
|
+ case duplicateKeychain = -25296
|
|
|
+ case duplicateCallback = -25297
|
|
|
+ case invalidCallback = -25298
|
|
|
+ case duplicateItem = -25299
|
|
|
+ case itemNotFound = -25300
|
|
|
+ case bufferTooSmall = -25301
|
|
|
+ case dataTooLarge = -25302
|
|
|
+ case noSuchAttr = -25303
|
|
|
+ case invalidItemRef = -25304
|
|
|
+ case invalidSearchRef = -25305
|
|
|
+ case noSuchClass = -25306
|
|
|
+ case noDefaultKeychain = -25307
|
|
|
+ case interactionNotAllowed = -25308
|
|
|
+ case readOnlyAttr = -25309
|
|
|
+ case wrongSecVersion = -25310
|
|
|
+ case keySizeNotAllowed = -25311
|
|
|
+ case noStorageModule = -25312
|
|
|
+ case noCertificateModule = -25313
|
|
|
+ case noPolicyModule = -25314
|
|
|
+ case interactionRequired = -25315
|
|
|
+ case dataNotAvailable = -25316
|
|
|
+ case dataNotModifiable = -25317
|
|
|
+ case createChainFailed = -25318
|
|
|
+ case invalidPrefsDomain = -25319
|
|
|
+ case inDarkWake = -25320
|
|
|
+ case aclNotSimple = -25240
|
|
|
+ case policyNotFound = -25241
|
|
|
+ case invalidTrustSetting = -25242
|
|
|
+ case noAccessForItem = -25243
|
|
|
+ case invalidOwnerEdit = -25244
|
|
|
+ case trustNotAvailable = -25245
|
|
|
+ case unsupportedFormat = -25256
|
|
|
+ case unknownFormat = -25257
|
|
|
+ case keyIsSensitive = -25258
|
|
|
+ case multiplePrivKeys = -25259
|
|
|
+ case passphraseRequired = -25260
|
|
|
+ case invalidPasswordRef = -25261
|
|
|
+ case invalidTrustSettings = -25262
|
|
|
+ case noTrustSettings = -25263
|
|
|
+ case pkcs12VerifyFailure = -25264
|
|
|
+ case invalidCertificate = -26265
|
|
|
+ case notSigner = -26267
|
|
|
+ case policyDenied = -26270
|
|
|
+ case invalidKey = -26274
|
|
|
+ case decode = -26275
|
|
|
+ case `internal` = -26276
|
|
|
+ case unsupportedAlgorithm = -26268
|
|
|
+ case unsupportedOperation = -26271
|
|
|
+ case unsupportedPadding = -26273
|
|
|
+ case itemInvalidKey = -34000
|
|
|
+ case itemInvalidKeyType = -34001
|
|
|
+ case itemInvalidValue = -34002
|
|
|
+ case itemClassMissing = -34003
|
|
|
+ case itemMatchUnsupported = -34004
|
|
|
+ case useItemListUnsupported = -34005
|
|
|
+ case useKeychainUnsupported = -34006
|
|
|
+ case useKeychainListUnsupported = -34007
|
|
|
+ case returnDataUnsupported = -34008
|
|
|
+ case returnAttributesUnsupported = -34009
|
|
|
+ case returnRefUnsupported = -34010
|
|
|
+ case returnPersitentRefUnsupported = -34011
|
|
|
+ case valueRefUnsupported = -34012
|
|
|
+ case valuePersistentRefUnsupported = -34013
|
|
|
+ case returnMissingPointer = -34014
|
|
|
+ case matchLimitUnsupported = -34015
|
|
|
+ case itemIllegalQuery = -34016
|
|
|
+ case waitForCallback = -34017
|
|
|
+ case missingEntitlement = -34018
|
|
|
+ case upgradePending = -34019
|
|
|
+ case mpSignatureInvalid = -25327
|
|
|
+ case otrTooOld = -25328
|
|
|
+ case otrIDTooNew = -25329
|
|
|
+ case serviceNotAvailable = -67585
|
|
|
+ case insufficientClientID = -67586
|
|
|
+ case deviceReset = -67587
|
|
|
+ case deviceFailed = -67588
|
|
|
+ case appleAddAppACLSubject = -67589
|
|
|
+ case applePublicKeyIncomplete = -67590
|
|
|
+ case appleSignatureMismatch = -67591
|
|
|
+ case appleInvalidKeyStartDate = -67592
|
|
|
+ case appleInvalidKeyEndDate = -67593
|
|
|
+ case conversionError = -67594
|
|
|
+ case appleSSLv2Rollback = -67595
|
|
|
+ case quotaExceeded = -67596
|
|
|
+ case fileTooBig = -67597
|
|
|
+ case invalidDatabaseBlob = -67598
|
|
|
+ case invalidKeyBlob = -67599
|
|
|
+ case incompatibleDatabaseBlob = -67600
|
|
|
+ case incompatibleKeyBlob = -67601
|
|
|
+ case hostNameMismatch = -67602
|
|
|
+ case unknownCriticalExtensionFlag = -67603
|
|
|
+ case noBasicConstraints = -67604
|
|
|
+ case noBasicConstraintsCA = -67605
|
|
|
+ case invalidAuthorityKeyID = -67606
|
|
|
+ case invalidSubjectKeyID = -67607
|
|
|
+ case invalidKeyUsageForPolicy = -67608
|
|
|
+ case invalidExtendedKeyUsage = -67609
|
|
|
+ case invalidIDLinkage = -67610
|
|
|
+ case pathLengthConstraintExceeded = -67611
|
|
|
+ case invalidRoot = -67612
|
|
|
+ case crlExpired = -67613
|
|
|
+ case crlNotValidYet = -67614
|
|
|
+ case crlNotFound = -67615
|
|
|
+ case crlServerDown = -67616
|
|
|
+ case crlBadURI = -67617
|
|
|
+ case unknownCertExtension = -67618
|
|
|
+ case unknownCRLExtension = -67619
|
|
|
+ case crlNotTrusted = -67620
|
|
|
+ case crlPolicyFailed = -67621
|
|
|
+ case idpFailure = -67622
|
|
|
+ case smimeEmailAddressesNotFound = -67623
|
|
|
+ case smimeBadExtendedKeyUsage = -67624
|
|
|
+ case smimeBadKeyUsage = -67625
|
|
|
+ case smimeKeyUsageNotCritical = -67626
|
|
|
+ case smimeNoEmailAddress = -67627
|
|
|
+ case smimeSubjAltNameNotCritical = -67628
|
|
|
+ case sslBadExtendedKeyUsage = -67629
|
|
|
+ case ocspBadResponse = -67630
|
|
|
+ case ocspBadRequest = -67631
|
|
|
+ case ocspUnavailable = -67632
|
|
|
+ case ocspStatusUnrecognized = -67633
|
|
|
+ case endOfData = -67634
|
|
|
+ case incompleteCertRevocationCheck = -67635
|
|
|
+ case networkFailure = -67636
|
|
|
+ case ocspNotTrustedToAnchor = -67637
|
|
|
+ case recordModified = -67638
|
|
|
+ case ocspSignatureError = -67639
|
|
|
+ case ocspNoSigner = -67640
|
|
|
+ case ocspResponderMalformedReq = -67641
|
|
|
+ case ocspResponderInternalError = -67642
|
|
|
+ case ocspResponderTryLater = -67643
|
|
|
+ case ocspResponderSignatureRequired = -67644
|
|
|
+ case ocspResponderUnauthorized = -67645
|
|
|
+ case ocspResponseNonceMismatch = -67646
|
|
|
+ case codeSigningBadCertChainLength = -67647
|
|
|
+ case codeSigningNoBasicConstraints = -67648
|
|
|
+ case codeSigningBadPathLengthConstraint = -67649
|
|
|
+ case codeSigningNoExtendedKeyUsage = -67650
|
|
|
+ case codeSigningDevelopment = -67651
|
|
|
+ case resourceSignBadCertChainLength = -67652
|
|
|
+ case resourceSignBadExtKeyUsage = -67653
|
|
|
+ case trustSettingDeny = -67654
|
|
|
+ case invalidSubjectName = -67655
|
|
|
+ case unknownQualifiedCertStatement = -67656
|
|
|
+ case mobileMeRequestQueued = -67657
|
|
|
+ case mobileMeRequestRedirected = -67658
|
|
|
+ case mobileMeServerError = -67659
|
|
|
+ case mobileMeServerNotAvailable = -67660
|
|
|
+ case mobileMeServerAlreadyExists = -67661
|
|
|
+ case mobileMeServerServiceErr = -67662
|
|
|
+ case mobileMeRequestAlreadyPending = -67663
|
|
|
+ case mobileMeNoRequestPending = -67664
|
|
|
+ case mobileMeCSRVerifyFailure = -67665
|
|
|
+ case mobileMeFailedConsistencyCheck = -67666
|
|
|
+ case notInitialized = -67667
|
|
|
+ case invalidHandleUsage = -67668
|
|
|
+ case pvcReferentNotFound = -67669
|
|
|
+ case functionIntegrityFail = -67670
|
|
|
+ case internalError = -67671
|
|
|
+ case memoryError = -67672
|
|
|
+ case invalidData = -67673
|
|
|
+ case mdsError = -67674
|
|
|
+ case invalidPointer = -67675
|
|
|
+ case selfCheckFailed = -67676
|
|
|
+ case functionFailed = -67677
|
|
|
+ case moduleManifestVerifyFailed = -67678
|
|
|
+ case invalidGUID = -67679
|
|
|
+ case invalidHandle = -67680
|
|
|
+ case invalidDBList = -67681
|
|
|
+ case invalidPassthroughID = -67682
|
|
|
+ case invalidNetworkAddress = -67683
|
|
|
+ case crlAlreadySigned = -67684
|
|
|
+ case invalidNumberOfFields = -67685
|
|
|
+ case verificationFailure = -67686
|
|
|
+ case unknownTag = -67687
|
|
|
+ case invalidSignature = -67688
|
|
|
+ case invalidName = -67689
|
|
|
+ case invalidCertificateRef = -67690
|
|
|
+ case invalidCertificateGroup = -67691
|
|
|
+ case tagNotFound = -67692
|
|
|
+ case invalidQuery = -67693
|
|
|
+ case invalidValue = -67694
|
|
|
+ case callbackFailed = -67695
|
|
|
+ case aclDeleteFailed = -67696
|
|
|
+ case aclReplaceFailed = -67697
|
|
|
+ case aclAddFailed = -67698
|
|
|
+ case aclChangeFailed = -67699
|
|
|
+ case invalidAccessCredentials = -67700
|
|
|
+ case invalidRecord = -67701
|
|
|
+ case invalidACL = -67702
|
|
|
+ case invalidSampleValue = -67703
|
|
|
+ case incompatibleVersion = -67704
|
|
|
+ case privilegeNotGranted = -67705
|
|
|
+ case invalidScope = -67706
|
|
|
+ case pvcAlreadyConfigured = -67707
|
|
|
+ case invalidPVC = -67708
|
|
|
+ case emmLoadFailed = -67709
|
|
|
+ case emmUnloadFailed = -67710
|
|
|
+ case addinLoadFailed = -67711
|
|
|
+ case invalidKeyRef = -67712
|
|
|
+ case invalidKeyHierarchy = -67713
|
|
|
+ case addinUnloadFailed = -67714
|
|
|
+ case libraryReferenceNotFound = -67715
|
|
|
+ case invalidAddinFunctionTable = -67716
|
|
|
+ case invalidServiceMask = -67717
|
|
|
+ case moduleNotLoaded = -67718
|
|
|
+ case invalidSubServiceID = -67719
|
|
|
+ case attributeNotInContext = -67720
|
|
|
+ case moduleManagerInitializeFailed = -67721
|
|
|
+ case moduleManagerNotFound = -67722
|
|
|
+ case eventNotificationCallbackNotFound = -67723
|
|
|
+ case inputLengthError = -67724
|
|
|
+ case outputLengthError = -67725
|
|
|
+ case privilegeNotSupported = -67726
|
|
|
+ case deviceError = -67727
|
|
|
+ case attachHandleBusy = -67728
|
|
|
+ case notLoggedIn = -67729
|
|
|
+ case algorithmMismatch = -67730
|
|
|
+ case keyUsageIncorrect = -67731
|
|
|
+ case keyBlobTypeIncorrect = -67732
|
|
|
+ case keyHeaderInconsistent = -67733
|
|
|
+ case unsupportedKeyFormat = -67734
|
|
|
+ case unsupportedKeySize = -67735
|
|
|
+ case invalidKeyUsageMask = -67736
|
|
|
+ case unsupportedKeyUsageMask = -67737
|
|
|
+ case invalidKeyAttributeMask = -67738
|
|
|
+ case unsupportedKeyAttributeMask = -67739
|
|
|
+ case invalidKeyLabel = -67740
|
|
|
+ case unsupportedKeyLabel = -67741
|
|
|
+ case invalidKeyFormat = -67742
|
|
|
+ case unsupportedVectorOfBuffers = -67743
|
|
|
+ case invalidInputVector = -67744
|
|
|
+ case invalidOutputVector = -67745
|
|
|
+ case invalidContext = -67746
|
|
|
+ case invalidAlgorithm = -67747
|
|
|
+ case invalidAttributeKey = -67748
|
|
|
+ case missingAttributeKey = -67749
|
|
|
+ case invalidAttributeInitVector = -67750
|
|
|
+ case missingAttributeInitVector = -67751
|
|
|
+ case invalidAttributeSalt = -67752
|
|
|
+ case missingAttributeSalt = -67753
|
|
|
+ case invalidAttributePadding = -67754
|
|
|
+ case missingAttributePadding = -67755
|
|
|
+ case invalidAttributeRandom = -67756
|
|
|
+ case missingAttributeRandom = -67757
|
|
|
+ case invalidAttributeSeed = -67758
|
|
|
+ case missingAttributeSeed = -67759
|
|
|
+ case invalidAttributePassphrase = -67760
|
|
|
+ case missingAttributePassphrase = -67761
|
|
|
+ case invalidAttributeKeyLength = -67762
|
|
|
+ case missingAttributeKeyLength = -67763
|
|
|
+ case invalidAttributeBlockSize = -67764
|
|
|
+ case missingAttributeBlockSize = -67765
|
|
|
+ case invalidAttributeOutputSize = -67766
|
|
|
+ case missingAttributeOutputSize = -67767
|
|
|
+ case invalidAttributeRounds = -67768
|
|
|
+ case missingAttributeRounds = -67769
|
|
|
+ case invalidAlgorithmParms = -67770
|
|
|
+ case missingAlgorithmParms = -67771
|
|
|
+ case invalidAttributeLabel = -67772
|
|
|
+ case missingAttributeLabel = -67773
|
|
|
+ case invalidAttributeKeyType = -67774
|
|
|
+ case missingAttributeKeyType = -67775
|
|
|
+ case invalidAttributeMode = -67776
|
|
|
+ case missingAttributeMode = -67777
|
|
|
+ case invalidAttributeEffectiveBits = -67778
|
|
|
+ case missingAttributeEffectiveBits = -67779
|
|
|
+ case invalidAttributeStartDate = -67780
|
|
|
+ case missingAttributeStartDate = -67781
|
|
|
+ case invalidAttributeEndDate = -67782
|
|
|
+ case missingAttributeEndDate = -67783
|
|
|
+ case invalidAttributeVersion = -67784
|
|
|
+ case missingAttributeVersion = -67785
|
|
|
+ case invalidAttributePrime = -67786
|
|
|
+ case missingAttributePrime = -67787
|
|
|
+ case invalidAttributeBase = -67788
|
|
|
+ case missingAttributeBase = -67789
|
|
|
+ case invalidAttributeSubprime = -67790
|
|
|
+ case missingAttributeSubprime = -67791
|
|
|
+ case invalidAttributeIterationCount = -67792
|
|
|
+ case missingAttributeIterationCount = -67793
|
|
|
+ case invalidAttributeDLDBHandle = -67794
|
|
|
+ case missingAttributeDLDBHandle = -67795
|
|
|
+ case invalidAttributeAccessCredentials = -67796
|
|
|
+ case missingAttributeAccessCredentials = -67797
|
|
|
+ case invalidAttributePublicKeyFormat = -67798
|
|
|
+ case missingAttributePublicKeyFormat = -67799
|
|
|
+ case invalidAttributePrivateKeyFormat = -67800
|
|
|
+ case missingAttributePrivateKeyFormat = -67801
|
|
|
+ case invalidAttributeSymmetricKeyFormat = -67802
|
|
|
+ case missingAttributeSymmetricKeyFormat = -67803
|
|
|
+ case invalidAttributeWrappedKeyFormat = -67804
|
|
|
+ case missingAttributeWrappedKeyFormat = -67805
|
|
|
+ case stagedOperationInProgress = -67806
|
|
|
+ case stagedOperationNotStarted = -67807
|
|
|
+ case verifyFailed = -67808
|
|
|
+ case querySizeUnknown = -67809
|
|
|
+ case blockSizeMismatch = -67810
|
|
|
+ case publicKeyInconsistent = -67811
|
|
|
+ case deviceVerifyFailed = -67812
|
|
|
+ case invalidLoginName = -67813
|
|
|
+ case alreadyLoggedIn = -67814
|
|
|
+ case invalidDigestAlgorithm = -67815
|
|
|
+ case invalidCRLGroup = -67816
|
|
|
+ case certificateCannotOperate = -67817
|
|
|
+ case certificateExpired = -67818
|
|
|
+ case certificateNotValidYet = -67819
|
|
|
+ case certificateRevoked = -67820
|
|
|
+ case certificateSuspended = -67821
|
|
|
+ case insufficientCredentials = -67822
|
|
|
+ case invalidAction = -67823
|
|
|
+ case invalidAuthority = -67824
|
|
|
+ case verifyActionFailed = -67825
|
|
|
+ case invalidCertAuthority = -67826
|
|
|
+ case invaldCRLAuthority = -67827
|
|
|
+ case invalidCRLEncoding = -67828
|
|
|
+ case invalidCRLType = -67829
|
|
|
+ case invalidCRL = -67830
|
|
|
+ case invalidFormType = -67831
|
|
|
+ case invalidID = -67832
|
|
|
+ case invalidIdentifier = -67833
|
|
|
+ case invalidIndex = -67834
|
|
|
+ case invalidPolicyIdentifiers = -67835
|
|
|
+ case invalidTimeString = -67836
|
|
|
+ case invalidReason = -67837
|
|
|
+ case invalidRequestInputs = -67838
|
|
|
+ case invalidResponseVector = -67839
|
|
|
+ case invalidStopOnPolicy = -67840
|
|
|
+ case invalidTuple = -67841
|
|
|
+ case multipleValuesUnsupported = -67842
|
|
|
+ case notTrusted = -67843
|
|
|
+ case noDefaultAuthority = -67844
|
|
|
+ case rejectedForm = -67845
|
|
|
+ case requestLost = -67846
|
|
|
+ case requestRejected = -67847
|
|
|
+ case unsupportedAddressType = -67848
|
|
|
+ case unsupportedService = -67849
|
|
|
+ case invalidTupleGroup = -67850
|
|
|
+ case invalidBaseACLs = -67851
|
|
|
+ case invalidTupleCredendtials = -67852
|
|
|
+ case invalidEncoding = -67853
|
|
|
+ case invalidValidityPeriod = -67854
|
|
|
+ case invalidRequestor = -67855
|
|
|
+ case requestDescriptor = -67856
|
|
|
+ case invalidBundleInfo = -67857
|
|
|
+ case invalidCRLIndex = -67858
|
|
|
+ case noFieldValues = -67859
|
|
|
+ case unsupportedFieldFormat = -67860
|
|
|
+ case unsupportedIndexInfo = -67861
|
|
|
+ case unsupportedLocality = -67862
|
|
|
+ case unsupportedNumAttributes = -67863
|
|
|
+ case unsupportedNumIndexes = -67864
|
|
|
+ case unsupportedNumRecordTypes = -67865
|
|
|
+ case fieldSpecifiedMultiple = -67866
|
|
|
+ case incompatibleFieldFormat = -67867
|
|
|
+ case invalidParsingModule = -67868
|
|
|
+ case databaseLocked = -67869
|
|
|
+ case datastoreIsOpen = -67870
|
|
|
+ case missingValue = -67871
|
|
|
+ case unsupportedQueryLimits = -67872
|
|
|
+ case unsupportedNumSelectionPreds = -67873
|
|
|
+ case unsupportedOperator = -67874
|
|
|
+ case invalidDBLocation = -67875
|
|
|
+ case invalidAccessRequest = -67876
|
|
|
+ case invalidIndexInfo = -67877
|
|
|
+ case invalidNewOwner = -67878
|
|
|
+ case invalidModifyMode = -67879
|
|
|
+ case missingRequiredExtension = -67880
|
|
|
+ case extendedKeyUsageNotCritical = -67881
|
|
|
+ case timestampMissing = -67882
|
|
|
+ case timestampInvalid = -67883
|
|
|
+ case timestampNotTrusted = -67884
|
|
|
+ case timestampServiceNotAvailable = -67885
|
|
|
+ case timestampBadAlg = -67886
|
|
|
+ case timestampBadRequest = -67887
|
|
|
+ case timestampBadDataFormat = -67888
|
|
|
+ case timestampTimeNotAvailable = -67889
|
|
|
+ case timestampUnacceptedPolicy = -67890
|
|
|
+ case timestampUnacceptedExtension = -67891
|
|
|
+ case timestampAddInfoNotAvailable = -67892
|
|
|
+ case timestampSystemFailure = -67893
|
|
|
+ case signingTimeMissing = -67894
|
|
|
+ case timestampRejection = -67895
|
|
|
+ case timestampWaiting = -67896
|
|
|
+ case timestampRevocationWarning = -67897
|
|
|
+ case timestampRevocationNotification = -67898
|
|
|
+ case unexpectedError = -99999
|
|
|
+}
|
|
|
+
|
|
|
+extension Status: RawRepresentable, CustomStringConvertible {
|
|
|
+
|
|
|
+ public init(status: OSStatus) {
|
|
|
+ if let mappedStatus = Status(rawValue: status) {
|
|
|
+ self = mappedStatus
|
|
|
+ } else {
|
|
|
+ self = .unexpectedError
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public var description: String {
|
|
|
+ switch self {
|
|
|
+ case .success:
|
|
|
+ return "No error."
|
|
|
+ case .unimplemented:
|
|
|
+ return "Function or operation not implemented."
|
|
|
+ case .diskFull:
|
|
|
+ return "The disk is full."
|
|
|
+ case .io:
|
|
|
+ return "I/O error (bummers)"
|
|
|
+ case .opWr:
|
|
|
+ return "file already open with with write permission"
|
|
|
+ case .param:
|
|
|
+ return "One or more parameters passed to a function were not valid."
|
|
|
+ case .wrPerm:
|
|
|
+ return "write permissions error"
|
|
|
+ case .allocate:
|
|
|
+ return "Failed to allocate memory."
|
|
|
+ case .userCanceled:
|
|
|
+ return "User canceled the operation."
|
|
|
+ case .badReq:
|
|
|
+ return "Bad parameter or invalid state for operation."
|
|
|
+ case .internalComponent:
|
|
|
+ return ""
|
|
|
+ case .notAvailable:
|
|
|
+ return "No keychain is available. You may need to restart your computer."
|
|
|
+ case .readOnly:
|
|
|
+ return "This keychain cannot be modified."
|
|
|
+ case .authFailed:
|
|
|
+ return "The user name or passphrase you entered is not correct."
|
|
|
+ case .noSuchKeychain:
|
|
|
+ return "The specified keychain could not be found."
|
|
|
+ case .invalidKeychain:
|
|
|
+ return "The specified keychain is not a valid keychain file."
|
|
|
+ case .duplicateKeychain:
|
|
|
+ return "A keychain with the same name already exists."
|
|
|
+ case .duplicateCallback:
|
|
|
+ return "The specified callback function is already installed."
|
|
|
+ case .invalidCallback:
|
|
|
+ return "The specified callback function is not valid."
|
|
|
+ case .duplicateItem:
|
|
|
+ return "The specified item already exists in the keychain."
|
|
|
+ case .itemNotFound:
|
|
|
+ return "The specified item could not be found in the keychain."
|
|
|
+ case .bufferTooSmall:
|
|
|
+ return "There is not enough memory available to use the specified item."
|
|
|
+ case .dataTooLarge:
|
|
|
+ return "This item contains information which is too large or in a format that cannot be displayed."
|
|
|
+ case .noSuchAttr:
|
|
|
+ return "The specified attribute does not exist."
|
|
|
+ case .invalidItemRef:
|
|
|
+ return "The specified item is no longer valid. It may have been deleted from the keychain."
|
|
|
+ case .invalidSearchRef:
|
|
|
+ return "Unable to search the current keychain."
|
|
|
+ case .noSuchClass:
|
|
|
+ return "The specified item does not appear to be a valid keychain item."
|
|
|
+ case .noDefaultKeychain:
|
|
|
+ return "A default keychain could not be found."
|
|
|
+ case .interactionNotAllowed:
|
|
|
+ return "User interaction is not allowed."
|
|
|
+ case .readOnlyAttr:
|
|
|
+ return "The specified attribute could not be modified."
|
|
|
+ case .wrongSecVersion:
|
|
|
+ return "This keychain was created by a different version of the system software and cannot be opened."
|
|
|
+ case .keySizeNotAllowed:
|
|
|
+ return "This item specifies a key size which is too large."
|
|
|
+ case .noStorageModule:
|
|
|
+ return "A required component (data storage module) could not be loaded. You may need to restart your computer."
|
|
|
+ case .noCertificateModule:
|
|
|
+ return "A required component (certificate module) could not be loaded. You may need to restart your computer."
|
|
|
+ case .noPolicyModule:
|
|
|
+ return "A required component (policy module) could not be loaded. You may need to restart your computer."
|
|
|
+ case .interactionRequired:
|
|
|
+ return "User interaction is required, but is currently not allowed."
|
|
|
+ case .dataNotAvailable:
|
|
|
+ return "The contents of this item cannot be retrieved."
|
|
|
+ case .dataNotModifiable:
|
|
|
+ return "The contents of this item cannot be modified."
|
|
|
+ case .createChainFailed:
|
|
|
+ return "One or more certificates required to validate this certificate cannot be found."
|
|
|
+ case .invalidPrefsDomain:
|
|
|
+ return "The specified preferences domain is not valid."
|
|
|
+ case .inDarkWake:
|
|
|
+ return "In dark wake, no UI possible"
|
|
|
+ case .aclNotSimple:
|
|
|
+ return "The specified access control list is not in standard (simple) form."
|
|
|
+ case .policyNotFound:
|
|
|
+ return "The specified policy cannot be found."
|
|
|
+ case .invalidTrustSetting:
|
|
|
+ return "The specified trust setting is invalid."
|
|
|
+ case .noAccessForItem:
|
|
|
+ return "The specified item has no access control."
|
|
|
+ case .invalidOwnerEdit:
|
|
|
+ return "Invalid attempt to change the owner of this item."
|
|
|
+ case .trustNotAvailable:
|
|
|
+ return "No trust results are available."
|
|
|
+ case .unsupportedFormat:
|
|
|
+ return "Import/Export format unsupported."
|
|
|
+ case .unknownFormat:
|
|
|
+ return "Unknown format in import."
|
|
|
+ case .keyIsSensitive:
|
|
|
+ return "Key material must be wrapped for export."
|
|
|
+ case .multiplePrivKeys:
|
|
|
+ return "An attempt was made to import multiple private keys."
|
|
|
+ case .passphraseRequired:
|
|
|
+ return "Passphrase is required for import/export."
|
|
|
+ case .invalidPasswordRef:
|
|
|
+ return "The password reference was invalid."
|
|
|
+ case .invalidTrustSettings:
|
|
|
+ return "The Trust Settings Record was corrupted."
|
|
|
+ case .noTrustSettings:
|
|
|
+ return "No Trust Settings were found."
|
|
|
+ case .pkcs12VerifyFailure:
|
|
|
+ return "MAC verification failed during PKCS12 import (wrong password?)"
|
|
|
+ case .invalidCertificate:
|
|
|
+ return "This certificate could not be decoded."
|
|
|
+ case .notSigner:
|
|
|
+ return "A certificate was not signed by its proposed parent."
|
|
|
+ case .policyDenied:
|
|
|
+ return "The certificate chain was not trusted due to a policy not accepting it."
|
|
|
+ case .invalidKey:
|
|
|
+ return "The provided key material was not valid."
|
|
|
+ case .decode:
|
|
|
+ return "Unable to decode the provided data."
|
|
|
+ case .`internal`:
|
|
|
+ return "An internal error occurred in the Security framework."
|
|
|
+ case .unsupportedAlgorithm:
|
|
|
+ return "An unsupported algorithm was encountered."
|
|
|
+ case .unsupportedOperation:
|
|
|
+ return "The operation you requested is not supported by this key."
|
|
|
+ case .unsupportedPadding:
|
|
|
+ return "The padding you requested is not supported."
|
|
|
+ case .itemInvalidKey:
|
|
|
+ return "A string key in dictionary is not one of the supported keys."
|
|
|
+ case .itemInvalidKeyType:
|
|
|
+ return "A key in a dictionary is neither a CFStringRef nor a CFNumberRef."
|
|
|
+ case .itemInvalidValue:
|
|
|
+ return "A value in a dictionary is an invalid (or unsupported) CF type."
|
|
|
+ case .itemClassMissing:
|
|
|
+ return "No kSecItemClass key was specified in a dictionary."
|
|
|
+ case .itemMatchUnsupported:
|
|
|
+ return "The caller passed one or more kSecMatch keys to a function which does not support matches."
|
|
|
+ case .useItemListUnsupported:
|
|
|
+ return "The caller passed in a kSecUseItemList key to a function which does not support it."
|
|
|
+ case .useKeychainUnsupported:
|
|
|
+ return "The caller passed in a kSecUseKeychain key to a function which does not support it."
|
|
|
+ case .useKeychainListUnsupported:
|
|
|
+ return "The caller passed in a kSecUseKeychainList key to a function which does not support it."
|
|
|
+ case .returnDataUnsupported:
|
|
|
+ return "The caller passed in a kSecReturnData key to a function which does not support it."
|
|
|
+ case .returnAttributesUnsupported:
|
|
|
+ return "The caller passed in a kSecReturnAttributes key to a function which does not support it."
|
|
|
+ case .returnRefUnsupported:
|
|
|
+ return "The caller passed in a kSecReturnRef key to a function which does not support it."
|
|
|
+ case .returnPersitentRefUnsupported:
|
|
|
+ return "The caller passed in a kSecReturnPersistentRef key to a function which does not support it."
|
|
|
+ case .valueRefUnsupported:
|
|
|
+ return "The caller passed in a kSecValueRef key to a function which does not support it."
|
|
|
+ case .valuePersistentRefUnsupported:
|
|
|
+ return "The caller passed in a kSecValuePersistentRef key to a function which does not support it."
|
|
|
+ case .returnMissingPointer:
|
|
|
+ return "The caller passed asked for something to be returned but did not pass in a result pointer."
|
|
|
+ case .matchLimitUnsupported:
|
|
|
+ return "The caller passed in a kSecMatchLimit key to a call which does not support limits."
|
|
|
+ case .itemIllegalQuery:
|
|
|
+ return "The caller passed in a query which contained too many keys."
|
|
|
+ case .waitForCallback:
|
|
|
+ return "This operation is incomplete, until the callback is invoked (not an error)."
|
|
|
+ case .missingEntitlement:
|
|
|
+ return "Internal error when a required entitlement isn't present, client has neither application-identifier nor keychain-access-groups entitlements."
|
|
|
+ case .upgradePending:
|
|
|
+ return "Error returned if keychain database needs a schema migration but the device is locked, clients should wait for a device unlock notification and retry the command."
|
|
|
+ case .mpSignatureInvalid:
|
|
|
+ return "Signature invalid on MP message"
|
|
|
+ case .otrTooOld:
|
|
|
+ return "Message is too old to use"
|
|
|
+ case .otrIDTooNew:
|
|
|
+ return "Key ID is too new to use! Message from the future?"
|
|
|
+ case .serviceNotAvailable:
|
|
|
+ return "The required service is not available."
|
|
|
+ case .insufficientClientID:
|
|
|
+ return "The client ID is not correct."
|
|
|
+ case .deviceReset:
|
|
|
+ return "A device reset has occurred."
|
|
|
+ case .deviceFailed:
|
|
|
+ return "A device failure has occurred."
|
|
|
+ case .appleAddAppACLSubject:
|
|
|
+ return "Adding an application ACL subject failed."
|
|
|
+ case .applePublicKeyIncomplete:
|
|
|
+ return "The public key is incomplete."
|
|
|
+ case .appleSignatureMismatch:
|
|
|
+ return "A signature mismatch has occurred."
|
|
|
+ case .appleInvalidKeyStartDate:
|
|
|
+ return "The specified key has an invalid start date."
|
|
|
+ case .appleInvalidKeyEndDate:
|
|
|
+ return "The specified key has an invalid end date."
|
|
|
+ case .conversionError:
|
|
|
+ return "A conversion error has occurred."
|
|
|
+ case .appleSSLv2Rollback:
|
|
|
+ return "A SSLv2 rollback error has occurred."
|
|
|
+ case .quotaExceeded:
|
|
|
+ return "The quota was exceeded."
|
|
|
+ case .fileTooBig:
|
|
|
+ return "The file is too big."
|
|
|
+ case .invalidDatabaseBlob:
|
|
|
+ return "The specified database has an invalid blob."
|
|
|
+ case .invalidKeyBlob:
|
|
|
+ return "The specified database has an invalid key blob."
|
|
|
+ case .incompatibleDatabaseBlob:
|
|
|
+ return "The specified database has an incompatible blob."
|
|
|
+ case .incompatibleKeyBlob:
|
|
|
+ return "The specified database has an incompatible key blob."
|
|
|
+ case .hostNameMismatch:
|
|
|
+ return "A host name mismatch has occurred."
|
|
|
+ case .unknownCriticalExtensionFlag:
|
|
|
+ return "There is an unknown critical extension flag."
|
|
|
+ case .noBasicConstraints:
|
|
|
+ return "No basic constraints were found."
|
|
|
+ case .noBasicConstraintsCA:
|
|
|
+ return "No basic CA constraints were found."
|
|
|
+ case .invalidAuthorityKeyID:
|
|
|
+ return "The authority key ID is not valid."
|
|
|
+ case .invalidSubjectKeyID:
|
|
|
+ return "The subject key ID is not valid."
|
|
|
+ case .invalidKeyUsageForPolicy:
|
|
|
+ return "The key usage is not valid for the specified policy."
|
|
|
+ case .invalidExtendedKeyUsage:
|
|
|
+ return "The extended key usage is not valid."
|
|
|
+ case .invalidIDLinkage:
|
|
|
+ return "The ID linkage is not valid."
|
|
|
+ case .pathLengthConstraintExceeded:
|
|
|
+ return "The path length constraint was exceeded."
|
|
|
+ case .invalidRoot:
|
|
|
+ return "The root or anchor certificate is not valid."
|
|
|
+ case .crlExpired:
|
|
|
+ return "The CRL has expired."
|
|
|
+ case .crlNotValidYet:
|
|
|
+ return "The CRL is not yet valid."
|
|
|
+ case .crlNotFound:
|
|
|
+ return "The CRL was not found."
|
|
|
+ case .crlServerDown:
|
|
|
+ return "The CRL server is down."
|
|
|
+ case .crlBadURI:
|
|
|
+ return "The CRL has a bad Uniform Resource Identifier."
|
|
|
+ case .unknownCertExtension:
|
|
|
+ return "An unknown certificate extension was encountered."
|
|
|
+ case .unknownCRLExtension:
|
|
|
+ return "An unknown CRL extension was encountered."
|
|
|
+ case .crlNotTrusted:
|
|
|
+ return "The CRL is not trusted."
|
|
|
+ case .crlPolicyFailed:
|
|
|
+ return "The CRL policy failed."
|
|
|
+ case .idpFailure:
|
|
|
+ return "The issuing distribution point was not valid."
|
|
|
+ case .smimeEmailAddressesNotFound:
|
|
|
+ return "An email address mismatch was encountered."
|
|
|
+ case .smimeBadExtendedKeyUsage:
|
|
|
+ return "The appropriate extended key usage for SMIME was not found."
|
|
|
+ case .smimeBadKeyUsage:
|
|
|
+ return "The key usage is not compatible with SMIME."
|
|
|
+ case .smimeKeyUsageNotCritical:
|
|
|
+ return "The key usage extension is not marked as critical."
|
|
|
+ case .smimeNoEmailAddress:
|
|
|
+ return "No email address was found in the certificate."
|
|
|
+ case .smimeSubjAltNameNotCritical:
|
|
|
+ return "The subject alternative name extension is not marked as critical."
|
|
|
+ case .sslBadExtendedKeyUsage:
|
|
|
+ return "The appropriate extended key usage for SSL was not found."
|
|
|
+ case .ocspBadResponse:
|
|
|
+ return "The OCSP response was incorrect or could not be parsed."
|
|
|
+ case .ocspBadRequest:
|
|
|
+ return "The OCSP request was incorrect or could not be parsed."
|
|
|
+ case .ocspUnavailable:
|
|
|
+ return "OCSP service is unavailable."
|
|
|
+ case .ocspStatusUnrecognized:
|
|
|
+ return "The OCSP server did not recognize this certificate."
|
|
|
+ case .endOfData:
|
|
|
+ return "An end-of-data was detected."
|
|
|
+ case .incompleteCertRevocationCheck:
|
|
|
+ return "An incomplete certificate revocation check occurred."
|
|
|
+ case .networkFailure:
|
|
|
+ return "A network failure occurred."
|
|
|
+ case .ocspNotTrustedToAnchor:
|
|
|
+ return "The OCSP response was not trusted to a root or anchor certificate."
|
|
|
+ case .recordModified:
|
|
|
+ return "The record was modified."
|
|
|
+ case .ocspSignatureError:
|
|
|
+ return "The OCSP response had an invalid signature."
|
|
|
+ case .ocspNoSigner:
|
|
|
+ return "The OCSP response had no signer."
|
|
|
+ case .ocspResponderMalformedReq:
|
|
|
+ return "The OCSP responder was given a malformed request."
|
|
|
+ case .ocspResponderInternalError:
|
|
|
+ return "The OCSP responder encountered an internal error."
|
|
|
+ case .ocspResponderTryLater:
|
|
|
+ return "The OCSP responder is busy, try again later."
|
|
|
+ case .ocspResponderSignatureRequired:
|
|
|
+ return "The OCSP responder requires a signature."
|
|
|
+ case .ocspResponderUnauthorized:
|
|
|
+ return "The OCSP responder rejected this request as unauthorized."
|
|
|
+ case .ocspResponseNonceMismatch:
|
|
|
+ return "The OCSP response nonce did not match the request."
|
|
|
+ case .codeSigningBadCertChainLength:
|
|
|
+ return "Code signing encountered an incorrect certificate chain length."
|
|
|
+ case .codeSigningNoBasicConstraints:
|
|
|
+ return "Code signing found no basic constraints."
|
|
|
+ case .codeSigningBadPathLengthConstraint:
|
|
|
+ return "Code signing encountered an incorrect path length constraint."
|
|
|
+ case .codeSigningNoExtendedKeyUsage:
|
|
|
+ return "Code signing found no extended key usage."
|
|
|
+ case .codeSigningDevelopment:
|
|
|
+ return "Code signing indicated use of a development-only certificate."
|
|
|
+ case .resourceSignBadCertChainLength:
|
|
|
+ return "Resource signing has encountered an incorrect certificate chain length."
|
|
|
+ case .resourceSignBadExtKeyUsage:
|
|
|
+ return "Resource signing has encountered an error in the extended key usage."
|
|
|
+ case .trustSettingDeny:
|
|
|
+ return "The trust setting for this policy was set to Deny."
|
|
|
+ case .invalidSubjectName:
|
|
|
+ return "An invalid certificate subject name was encountered."
|
|
|
+ case .unknownQualifiedCertStatement:
|
|
|
+ return "An unknown qualified certificate statement was encountered."
|
|
|
+ case .mobileMeRequestQueued:
|
|
|
+ return "The MobileMe request will be sent during the next connection."
|
|
|
+ case .mobileMeRequestRedirected:
|
|
|
+ return "The MobileMe request was redirected."
|
|
|
+ case .mobileMeServerError:
|
|
|
+ return "A MobileMe server error occurred."
|
|
|
+ case .mobileMeServerNotAvailable:
|
|
|
+ return "The MobileMe server is not available."
|
|
|
+ case .mobileMeServerAlreadyExists:
|
|
|
+ return "The MobileMe server reported that the item already exists."
|
|
|
+ case .mobileMeServerServiceErr:
|
|
|
+ return "A MobileMe service error has occurred."
|
|
|
+ case .mobileMeRequestAlreadyPending:
|
|
|
+ return "A MobileMe request is already pending."
|
|
|
+ case .mobileMeNoRequestPending:
|
|
|
+ return "MobileMe has no request pending."
|
|
|
+ case .mobileMeCSRVerifyFailure:
|
|
|
+ return "A MobileMe CSR verification failure has occurred."
|
|
|
+ case .mobileMeFailedConsistencyCheck:
|
|
|
+ return "MobileMe has found a failed consistency check."
|
|
|
+ case .notInitialized:
|
|
|
+ return "A function was called without initializing CSSM."
|
|
|
+ case .invalidHandleUsage:
|
|
|
+ return "The CSSM handle does not match with the service type."
|
|
|
+ case .pvcReferentNotFound:
|
|
|
+ return "A reference to the calling module was not found in the list of authorized callers."
|
|
|
+ case .functionIntegrityFail:
|
|
|
+ return "A function address was not within the verified module."
|
|
|
+ case .internalError:
|
|
|
+ return "An internal error has occurred."
|
|
|
+ case .memoryError:
|
|
|
+ return "A memory error has occurred."
|
|
|
+ case .invalidData:
|
|
|
+ return "Invalid data was encountered."
|
|
|
+ case .mdsError:
|
|
|
+ return "A Module Directory Service error has occurred."
|
|
|
+ case .invalidPointer:
|
|
|
+ return "An invalid pointer was encountered."
|
|
|
+ case .selfCheckFailed:
|
|
|
+ return "Self-check has failed."
|
|
|
+ case .functionFailed:
|
|
|
+ return "A function has failed."
|
|
|
+ case .moduleManifestVerifyFailed:
|
|
|
+ return "A module manifest verification failure has occurred."
|
|
|
+ case .invalidGUID:
|
|
|
+ return "An invalid GUID was encountered."
|
|
|
+ case .invalidHandle:
|
|
|
+ return "An invalid handle was encountered."
|
|
|
+ case .invalidDBList:
|
|
|
+ return "An invalid DB list was encountered."
|
|
|
+ case .invalidPassthroughID:
|
|
|
+ return "An invalid passthrough ID was encountered."
|
|
|
+ case .invalidNetworkAddress:
|
|
|
+ return "An invalid network address was encountered."
|
|
|
+ case .crlAlreadySigned:
|
|
|
+ return "The certificate revocation list is already signed."
|
|
|
+ case .invalidNumberOfFields:
|
|
|
+ return "An invalid number of fields were encountered."
|
|
|
+ case .verificationFailure:
|
|
|
+ return "A verification failure occurred."
|
|
|
+ case .unknownTag:
|
|
|
+ return "An unknown tag was encountered."
|
|
|
+ case .invalidSignature:
|
|
|
+ return "An invalid signature was encountered."
|
|
|
+ case .invalidName:
|
|
|
+ return "An invalid name was encountered."
|
|
|
+ case .invalidCertificateRef:
|
|
|
+ return "An invalid certificate reference was encountered."
|
|
|
+ case .invalidCertificateGroup:
|
|
|
+ return "An invalid certificate group was encountered."
|
|
|
+ case .tagNotFound:
|
|
|
+ return "The specified tag was not found."
|
|
|
+ case .invalidQuery:
|
|
|
+ return "The specified query was not valid."
|
|
|
+ case .invalidValue:
|
|
|
+ return "An invalid value was detected."
|
|
|
+ case .callbackFailed:
|
|
|
+ return "A callback has failed."
|
|
|
+ case .aclDeleteFailed:
|
|
|
+ return "An ACL delete operation has failed."
|
|
|
+ case .aclReplaceFailed:
|
|
|
+ return "An ACL replace operation has failed."
|
|
|
+ case .aclAddFailed:
|
|
|
+ return "An ACL add operation has failed."
|
|
|
+ case .aclChangeFailed:
|
|
|
+ return "An ACL change operation has failed."
|
|
|
+ case .invalidAccessCredentials:
|
|
|
+ return "Invalid access credentials were encountered."
|
|
|
+ case .invalidRecord:
|
|
|
+ return "An invalid record was encountered."
|
|
|
+ case .invalidACL:
|
|
|
+ return "An invalid ACL was encountered."
|
|
|
+ case .invalidSampleValue:
|
|
|
+ return "An invalid sample value was encountered."
|
|
|
+ case .incompatibleVersion:
|
|
|
+ return "An incompatible version was encountered."
|
|
|
+ case .privilegeNotGranted:
|
|
|
+ return "The privilege was not granted."
|
|
|
+ case .invalidScope:
|
|
|
+ return "An invalid scope was encountered."
|
|
|
+ case .pvcAlreadyConfigured:
|
|
|
+ return "The PVC is already configured."
|
|
|
+ case .invalidPVC:
|
|
|
+ return "An invalid PVC was encountered."
|
|
|
+ case .emmLoadFailed:
|
|
|
+ return "The EMM load has failed."
|
|
|
+ case .emmUnloadFailed:
|
|
|
+ return "The EMM unload has failed."
|
|
|
+ case .addinLoadFailed:
|
|
|
+ return "The add-in load operation has failed."
|
|
|
+ case .invalidKeyRef:
|
|
|
+ return "An invalid key was encountered."
|
|
|
+ case .invalidKeyHierarchy:
|
|
|
+ return "An invalid key hierarchy was encountered."
|
|
|
+ case .addinUnloadFailed:
|
|
|
+ return "The add-in unload operation has failed."
|
|
|
+ case .libraryReferenceNotFound:
|
|
|
+ return "A library reference was not found."
|
|
|
+ case .invalidAddinFunctionTable:
|
|
|
+ return "An invalid add-in function table was encountered."
|
|
|
+ case .invalidServiceMask:
|
|
|
+ return "An invalid service mask was encountered."
|
|
|
+ case .moduleNotLoaded:
|
|
|
+ return "A module was not loaded."
|
|
|
+ case .invalidSubServiceID:
|
|
|
+ return "An invalid subservice ID was encountered."
|
|
|
+ case .attributeNotInContext:
|
|
|
+ return "An attribute was not in the context."
|
|
|
+ case .moduleManagerInitializeFailed:
|
|
|
+ return "A module failed to initialize."
|
|
|
+ case .moduleManagerNotFound:
|
|
|
+ return "A module was not found."
|
|
|
+ case .eventNotificationCallbackNotFound:
|
|
|
+ return "An event notification callback was not found."
|
|
|
+ case .inputLengthError:
|
|
|
+ return "An input length error was encountered."
|
|
|
+ case .outputLengthError:
|
|
|
+ return "An output length error was encountered."
|
|
|
+ case .privilegeNotSupported:
|
|
|
+ return "The privilege is not supported."
|
|
|
+ case .deviceError:
|
|
|
+ return "A device error was encountered."
|
|
|
+ case .attachHandleBusy:
|
|
|
+ return "The CSP handle was busy."
|
|
|
+ case .notLoggedIn:
|
|
|
+ return "You are not logged in."
|
|
|
+ case .algorithmMismatch:
|
|
|
+ return "An algorithm mismatch was encountered."
|
|
|
+ case .keyUsageIncorrect:
|
|
|
+ return "The key usage is incorrect."
|
|
|
+ case .keyBlobTypeIncorrect:
|
|
|
+ return "The key blob type is incorrect."
|
|
|
+ case .keyHeaderInconsistent:
|
|
|
+ return "The key header is inconsistent."
|
|
|
+ case .unsupportedKeyFormat:
|
|
|
+ return "The key header format is not supported."
|
|
|
+ case .unsupportedKeySize:
|
|
|
+ return "The key size is not supported."
|
|
|
+ case .invalidKeyUsageMask:
|
|
|
+ return "The key usage mask is not valid."
|
|
|
+ case .unsupportedKeyUsageMask:
|
|
|
+ return "The key usage mask is not supported."
|
|
|
+ case .invalidKeyAttributeMask:
|
|
|
+ return "The key attribute mask is not valid."
|
|
|
+ case .unsupportedKeyAttributeMask:
|
|
|
+ return "The key attribute mask is not supported."
|
|
|
+ case .invalidKeyLabel:
|
|
|
+ return "The key label is not valid."
|
|
|
+ case .unsupportedKeyLabel:
|
|
|
+ return "The key label is not supported."
|
|
|
+ case .invalidKeyFormat:
|
|
|
+ return "The key format is not valid."
|
|
|
+ case .unsupportedVectorOfBuffers:
|
|
|
+ return "The vector of buffers is not supported."
|
|
|
+ case .invalidInputVector:
|
|
|
+ return "The input vector is not valid."
|
|
|
+ case .invalidOutputVector:
|
|
|
+ return "The output vector is not valid."
|
|
|
+ case .invalidContext:
|
|
|
+ return "An invalid context was encountered."
|
|
|
+ case .invalidAlgorithm:
|
|
|
+ return "An invalid algorithm was encountered."
|
|
|
+ case .invalidAttributeKey:
|
|
|
+ return "A key attribute was not valid."
|
|
|
+ case .missingAttributeKey:
|
|
|
+ return "A key attribute was missing."
|
|
|
+ case .invalidAttributeInitVector:
|
|
|
+ return "An init vector attribute was not valid."
|
|
|
+ case .missingAttributeInitVector:
|
|
|
+ return "An init vector attribute was missing."
|
|
|
+ case .invalidAttributeSalt:
|
|
|
+ return "A salt attribute was not valid."
|
|
|
+ case .missingAttributeSalt:
|
|
|
+ return "A salt attribute was missing."
|
|
|
+ case .invalidAttributePadding:
|
|
|
+ return "A padding attribute was not valid."
|
|
|
+ case .missingAttributePadding:
|
|
|
+ return "A padding attribute was missing."
|
|
|
+ case .invalidAttributeRandom:
|
|
|
+ return "A random number attribute was not valid."
|
|
|
+ case .missingAttributeRandom:
|
|
|
+ return "A random number attribute was missing."
|
|
|
+ case .invalidAttributeSeed:
|
|
|
+ return "A seed attribute was not valid."
|
|
|
+ case .missingAttributeSeed:
|
|
|
+ return "A seed attribute was missing."
|
|
|
+ case .invalidAttributePassphrase:
|
|
|
+ return "A passphrase attribute was not valid."
|
|
|
+ case .missingAttributePassphrase:
|
|
|
+ return "A passphrase attribute was missing."
|
|
|
+ case .invalidAttributeKeyLength:
|
|
|
+ return "A key length attribute was not valid."
|
|
|
+ case .missingAttributeKeyLength:
|
|
|
+ return "A key length attribute was missing."
|
|
|
+ case .invalidAttributeBlockSize:
|
|
|
+ return "A block size attribute was not valid."
|
|
|
+ case .missingAttributeBlockSize:
|
|
|
+ return "A block size attribute was missing."
|
|
|
+ case .invalidAttributeOutputSize:
|
|
|
+ return "An output size attribute was not valid."
|
|
|
+ case .missingAttributeOutputSize:
|
|
|
+ return "An output size attribute was missing."
|
|
|
+ case .invalidAttributeRounds:
|
|
|
+ return "The number of rounds attribute was not valid."
|
|
|
+ case .missingAttributeRounds:
|
|
|
+ return "The number of rounds attribute was missing."
|
|
|
+ case .invalidAlgorithmParms:
|
|
|
+ return "An algorithm parameters attribute was not valid."
|
|
|
+ case .missingAlgorithmParms:
|
|
|
+ return "An algorithm parameters attribute was missing."
|
|
|
+ case .invalidAttributeLabel:
|
|
|
+ return "A label attribute was not valid."
|
|
|
+ case .missingAttributeLabel:
|
|
|
+ return "A label attribute was missing."
|
|
|
+ case .invalidAttributeKeyType:
|
|
|
+ return "A key type attribute was not valid."
|
|
|
+ case .missingAttributeKeyType:
|
|
|
+ return "A key type attribute was missing."
|
|
|
+ case .invalidAttributeMode:
|
|
|
+ return "A mode attribute was not valid."
|
|
|
+ case .missingAttributeMode:
|
|
|
+ return "A mode attribute was missing."
|
|
|
+ case .invalidAttributeEffectiveBits:
|
|
|
+ return "An effective bits attribute was not valid."
|
|
|
+ case .missingAttributeEffectiveBits:
|
|
|
+ return "An effective bits attribute was missing."
|
|
|
+ case .invalidAttributeStartDate:
|
|
|
+ return "A start date attribute was not valid."
|
|
|
+ case .missingAttributeStartDate:
|
|
|
+ return "A start date attribute was missing."
|
|
|
+ case .invalidAttributeEndDate:
|
|
|
+ return "An end date attribute was not valid."
|
|
|
+ case .missingAttributeEndDate:
|
|
|
+ return "An end date attribute was missing."
|
|
|
+ case .invalidAttributeVersion:
|
|
|
+ return "A version attribute was not valid."
|
|
|
+ case .missingAttributeVersion:
|
|
|
+ return "A version attribute was missing."
|
|
|
+ case .invalidAttributePrime:
|
|
|
+ return "A prime attribute was not valid."
|
|
|
+ case .missingAttributePrime:
|
|
|
+ return "A prime attribute was missing."
|
|
|
+ case .invalidAttributeBase:
|
|
|
+ return "A base attribute was not valid."
|
|
|
+ case .missingAttributeBase:
|
|
|
+ return "A base attribute was missing."
|
|
|
+ case .invalidAttributeSubprime:
|
|
|
+ return "A subprime attribute was not valid."
|
|
|
+ case .missingAttributeSubprime:
|
|
|
+ return "A subprime attribute was missing."
|
|
|
+ case .invalidAttributeIterationCount:
|
|
|
+ return "An iteration count attribute was not valid."
|
|
|
+ case .missingAttributeIterationCount:
|
|
|
+ return "An iteration count attribute was missing."
|
|
|
+ case .invalidAttributeDLDBHandle:
|
|
|
+ return "A database handle attribute was not valid."
|
|
|
+ case .missingAttributeDLDBHandle:
|
|
|
+ return "A database handle attribute was missing."
|
|
|
+ case .invalidAttributeAccessCredentials:
|
|
|
+ return "An access credentials attribute was not valid."
|
|
|
+ case .missingAttributeAccessCredentials:
|
|
|
+ return "An access credentials attribute was missing."
|
|
|
+ case .invalidAttributePublicKeyFormat:
|
|
|
+ return "A public key format attribute was not valid."
|
|
|
+ case .missingAttributePublicKeyFormat:
|
|
|
+ return "A public key format attribute was missing."
|
|
|
+ case .invalidAttributePrivateKeyFormat:
|
|
|
+ return "A private key format attribute was not valid."
|
|
|
+ case .missingAttributePrivateKeyFormat:
|
|
|
+ return "A private key format attribute was missing."
|
|
|
+ case .invalidAttributeSymmetricKeyFormat:
|
|
|
+ return "A symmetric key format attribute was not valid."
|
|
|
+ case .missingAttributeSymmetricKeyFormat:
|
|
|
+ return "A symmetric key format attribute was missing."
|
|
|
+ case .invalidAttributeWrappedKeyFormat:
|
|
|
+ return "A wrapped key format attribute was not valid."
|
|
|
+ case .missingAttributeWrappedKeyFormat:
|
|
|
+ return "A wrapped key format attribute was missing."
|
|
|
+ case .stagedOperationInProgress:
|
|
|
+ return "A staged operation is in progress."
|
|
|
+ case .stagedOperationNotStarted:
|
|
|
+ return "A staged operation was not started."
|
|
|
+ case .verifyFailed:
|
|
|
+ return "A cryptographic verification failure has occurred."
|
|
|
+ case .querySizeUnknown:
|
|
|
+ return "The query size is unknown."
|
|
|
+ case .blockSizeMismatch:
|
|
|
+ return "A block size mismatch occurred."
|
|
|
+ case .publicKeyInconsistent:
|
|
|
+ return "The public key was inconsistent."
|
|
|
+ case .deviceVerifyFailed:
|
|
|
+ return "A device verification failure has occurred."
|
|
|
+ case .invalidLoginName:
|
|
|
+ return "An invalid login name was detected."
|
|
|
+ case .alreadyLoggedIn:
|
|
|
+ return "The user is already logged in."
|
|
|
+ case .invalidDigestAlgorithm:
|
|
|
+ return "An invalid digest algorithm was detected."
|
|
|
+ case .invalidCRLGroup:
|
|
|
+ return "An invalid CRL group was detected."
|
|
|
+ case .certificateCannotOperate:
|
|
|
+ return "The certificate cannot operate."
|
|
|
+ case .certificateExpired:
|
|
|
+ return "An expired certificate was detected."
|
|
|
+ case .certificateNotValidYet:
|
|
|
+ return "The certificate is not yet valid."
|
|
|
+ case .certificateRevoked:
|
|
|
+ return "The certificate was revoked."
|
|
|
+ case .certificateSuspended:
|
|
|
+ return "The certificate was suspended."
|
|
|
+ case .insufficientCredentials:
|
|
|
+ return "Insufficient credentials were detected."
|
|
|
+ case .invalidAction:
|
|
|
+ return "The action was not valid."
|
|
|
+ case .invalidAuthority:
|
|
|
+ return "The authority was not valid."
|
|
|
+ case .verifyActionFailed:
|
|
|
+ return "A verify action has failed."
|
|
|
+ case .invalidCertAuthority:
|
|
|
+ return "The certificate authority was not valid."
|
|
|
+ case .invaldCRLAuthority:
|
|
|
+ return "The CRL authority was not valid."
|
|
|
+ case .invalidCRLEncoding:
|
|
|
+ return "The CRL encoding was not valid."
|
|
|
+ case .invalidCRLType:
|
|
|
+ return "The CRL type was not valid."
|
|
|
+ case .invalidCRL:
|
|
|
+ return "The CRL was not valid."
|
|
|
+ case .invalidFormType:
|
|
|
+ return "The form type was not valid."
|
|
|
+ case .invalidID:
|
|
|
+ return "The ID was not valid."
|
|
|
+ case .invalidIdentifier:
|
|
|
+ return "The identifier was not valid."
|
|
|
+ case .invalidIndex:
|
|
|
+ return "The index was not valid."
|
|
|
+ case .invalidPolicyIdentifiers:
|
|
|
+ return "The policy identifiers are not valid."
|
|
|
+ case .invalidTimeString:
|
|
|
+ return "The time specified was not valid."
|
|
|
+ case .invalidReason:
|
|
|
+ return "The trust policy reason was not valid."
|
|
|
+ case .invalidRequestInputs:
|
|
|
+ return "The request inputs are not valid."
|
|
|
+ case .invalidResponseVector:
|
|
|
+ return "The response vector was not valid."
|
|
|
+ case .invalidStopOnPolicy:
|
|
|
+ return "The stop-on policy was not valid."
|
|
|
+ case .invalidTuple:
|
|
|
+ return "The tuple was not valid."
|
|
|
+ case .multipleValuesUnsupported:
|
|
|
+ return "Multiple values are not supported."
|
|
|
+ case .notTrusted:
|
|
|
+ return "The trust policy was not trusted."
|
|
|
+ case .noDefaultAuthority:
|
|
|
+ return "No default authority was detected."
|
|
|
+ case .rejectedForm:
|
|
|
+ return "The trust policy had a rejected form."
|
|
|
+ case .requestLost:
|
|
|
+ return "The request was lost."
|
|
|
+ case .requestRejected:
|
|
|
+ return "The request was rejected."
|
|
|
+ case .unsupportedAddressType:
|
|
|
+ return "The address type is not supported."
|
|
|
+ case .unsupportedService:
|
|
|
+ return "The service is not supported."
|
|
|
+ case .invalidTupleGroup:
|
|
|
+ return "The tuple group was not valid."
|
|
|
+ case .invalidBaseACLs:
|
|
|
+ return "The base ACLs are not valid."
|
|
|
+ case .invalidTupleCredendtials:
|
|
|
+ return "The tuple credentials are not valid."
|
|
|
+ case .invalidEncoding:
|
|
|
+ return "The encoding was not valid."
|
|
|
+ case .invalidValidityPeriod:
|
|
|
+ return "The validity period was not valid."
|
|
|
+ case .invalidRequestor:
|
|
|
+ return "The requestor was not valid."
|
|
|
+ case .requestDescriptor:
|
|
|
+ return "The request descriptor was not valid."
|
|
|
+ case .invalidBundleInfo:
|
|
|
+ return "The bundle information was not valid."
|
|
|
+ case .invalidCRLIndex:
|
|
|
+ return "The CRL index was not valid."
|
|
|
+ case .noFieldValues:
|
|
|
+ return "No field values were detected."
|
|
|
+ case .unsupportedFieldFormat:
|
|
|
+ return "The field format is not supported."
|
|
|
+ case .unsupportedIndexInfo:
|
|
|
+ return "The index information is not supported."
|
|
|
+ case .unsupportedLocality:
|
|
|
+ return "The locality is not supported."
|
|
|
+ case .unsupportedNumAttributes:
|
|
|
+ return "The number of attributes is not supported."
|
|
|
+ case .unsupportedNumIndexes:
|
|
|
+ return "The number of indexes is not supported."
|
|
|
+ case .unsupportedNumRecordTypes:
|
|
|
+ return "The number of record types is not supported."
|
|
|
+ case .fieldSpecifiedMultiple:
|
|
|
+ return "Too many fields were specified."
|
|
|
+ case .incompatibleFieldFormat:
|
|
|
+ return "The field format was incompatible."
|
|
|
+ case .invalidParsingModule:
|
|
|
+ return "The parsing module was not valid."
|
|
|
+ case .databaseLocked:
|
|
|
+ return "The database is locked."
|
|
|
+ case .datastoreIsOpen:
|
|
|
+ return "The data store is open."
|
|
|
+ case .missingValue:
|
|
|
+ return "A missing value was detected."
|
|
|
+ case .unsupportedQueryLimits:
|
|
|
+ return "The query limits are not supported."
|
|
|
+ case .unsupportedNumSelectionPreds:
|
|
|
+ return "The number of selection predicates is not supported."
|
|
|
+ case .unsupportedOperator:
|
|
|
+ return "The operator is not supported."
|
|
|
+ case .invalidDBLocation:
|
|
|
+ return "The database location is not valid."
|
|
|
+ case .invalidAccessRequest:
|
|
|
+ return "The access request is not valid."
|
|
|
+ case .invalidIndexInfo:
|
|
|
+ return "The index information is not valid."
|
|
|
+ case .invalidNewOwner:
|
|
|
+ return "The new owner is not valid."
|
|
|
+ case .invalidModifyMode:
|
|
|
+ return "The modify mode is not valid."
|
|
|
+ case .missingRequiredExtension:
|
|
|
+ return "A required certificate extension is missing."
|
|
|
+ case .extendedKeyUsageNotCritical:
|
|
|
+ return "The extended key usage extension was not marked critical."
|
|
|
+ case .timestampMissing:
|
|
|
+ return "A timestamp was expected but was not found."
|
|
|
+ case .timestampInvalid:
|
|
|
+ return "The timestamp was not valid."
|
|
|
+ case .timestampNotTrusted:
|
|
|
+ return "The timestamp was not trusted."
|
|
|
+ case .timestampServiceNotAvailable:
|
|
|
+ return "The timestamp service is not available."
|
|
|
+ case .timestampBadAlg:
|
|
|
+ return "An unrecognized or unsupported Algorithm Identifier in timestamp."
|
|
|
+ case .timestampBadRequest:
|
|
|
+ return "The timestamp transaction is not permitted or supported."
|
|
|
+ case .timestampBadDataFormat:
|
|
|
+ return "The timestamp data submitted has the wrong format."
|
|
|
+ case .timestampTimeNotAvailable:
|
|
|
+ return "The time source for the Timestamp Authority is not available."
|
|
|
+ case .timestampUnacceptedPolicy:
|
|
|
+ return "The requested policy is not supported by the Timestamp Authority."
|
|
|
+ case .timestampUnacceptedExtension:
|
|
|
+ return "The requested extension is not supported by the Timestamp Authority."
|
|
|
+ case .timestampAddInfoNotAvailable:
|
|
|
+ return "The additional information requested is not available."
|
|
|
+ case .timestampSystemFailure:
|
|
|
+ return "The timestamp request cannot be handled due to system failure."
|
|
|
+ case .signingTimeMissing:
|
|
|
+ return "A signing time was expected but was not found."
|
|
|
+ case .timestampRejection:
|
|
|
+ return "A timestamp transaction was rejected."
|
|
|
+ case .timestampWaiting:
|
|
|
+ return "A timestamp transaction is waiting."
|
|
|
+ case .timestampRevocationWarning:
|
|
|
+ return "A timestamp authority revocation warning was issued."
|
|
|
+ case .timestampRevocationNotification:
|
|
|
+ return "A timestamp authority revocation notification was issued."
|
|
|
+ case .unexpectedError:
|
|
|
+ return "Unexpected error has occurred."
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension Status: CustomNSError {
|
|
|
+ public static let errorDomain = KeychainAccessErrorDomain
|
|
|
+
|
|
|
+ public var errorCode: Int {
|
|
|
+ return Int(rawValue)
|
|
|
+ }
|
|
|
+
|
|
|
+ public var errorUserInfo: [String : Any] {
|
|
|
+ return [NSLocalizedDescriptionKey: description]
|
|
|
+ }
|
|
|
+}
|