From 1ab3aafb6f2b816105a097762c005a04551a0a82 Mon Sep 17 00:00:00 2001 From: Colin Morelli Date: Sun, 10 Jul 2016 00:23:21 -0400 Subject: [PATCH 1/6] Adding accessibility selection --- Heimdall/Heimdall.swift | 98 ++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/Heimdall/Heimdall.swift b/Heimdall/Heimdall.swift index d679ea3..cbad2e2 100644 --- a/Heimdall/Heimdall.swift +++ b/Heimdall/Heimdall.swift @@ -41,7 +41,8 @@ public class Heimdall { private let publicTag: String private var privateTag: String? private var scope: ScopeOptions - + private var accessibility: KeypairAccessibility + /// /// Create an instance with data for the public key, /// the keychain is updated with the tag given (call .destroy() to remove) @@ -53,24 +54,24 @@ public class Heimdall { /// /// - returns: Heimdall instance that can handle only public key operations /// - public convenience init?(publicTag: String, publicKeyData: NSData? = nil) { - if let existingData = Heimdall.obtainKeyData(publicTag) { - // Compare agains the new data (optional) - if let newData = publicKeyData?.dataByStrippingX509Header() where !existingData.isEqualToData(newData) { - Heimdall.updateKey(publicTag, data: newData) - } - - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil) - } else if let data = publicKeyData?.dataByStrippingX509Header(), _ = Heimdall.insertPublicKey(publicTag, data: data) { - // Successfully created the new key - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil) - } else { - // Call the init, although returning nil - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil) - return nil - } + public convenience init?(publicTag: String, publicKeyData: NSData? = nil, accessibility: KeypairAccessibility = .WhenUnlocked) { + if let existingData = Heimdall.obtainKeyData(publicTag) { + // Compare agains the new data (optional) + if let newData = publicKeyData?.dataByStrippingX509Header() where !existingData.isEqualToData(newData) { + Heimdall.updateKey(publicTag, data: newData) + } + + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) + } else if let data = publicKeyData?.dataByStrippingX509Header(), _ = Heimdall.insertPublicKey(publicTag, accessibility: accessibility, data: data) { + // Successfully created the new key + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) + } else { + // Call the init, although returning nil + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) + return nil + } } - + /// /// Create an instance with the modulus and exponent of the public key /// the resulting key is added to the keychain (call .destroy() to remove) @@ -98,10 +99,10 @@ public class Heimdall { /// /// - returns: Heimdall instance that can handle both private and public key operations /// - public convenience init?(tagPrefix: String, keySize: Int = 2048) { + public convenience init?(tagPrefix: String, keySize: Int = 2048, accessibility: KeypairAccessibility = .WhenUnlocked) { self.init(publicTag: tagPrefix, privateTag: tagPrefix + ".private", keySize: keySize) } - + /// /// Create an instane with public and private key tags, if the key pair does not exist /// the keys will be generated @@ -113,20 +114,22 @@ public class Heimdall { /// /// - returns: Heimdall instance ready for both public and private key operations /// - public convenience init?(publicTag: String, privateTag: String, keySize: Int = 2048) { - self.init(scope: ScopeOptions.All, publicTag: publicTag, privateTag: privateTag) - + public convenience init?(publicTag: String, privateTag: String, keySize: Int = 2048, accessibility: KeypairAccessibility = .WhenUnlocked) { + self.init(scope: ScopeOptions.All, publicTag: publicTag, privateTag: privateTag, accessibility: accessibility) + if Heimdall.obtainKey(publicTag) == nil || Heimdall.obtainKey(privateTag) == nil { - if Heimdall.generateKeyPair(publicTag, privateTag: privateTag, keySize: keySize) == nil { + if Heimdall.generateKeyPair(publicTag, privateTag: privateTag, keySize: keySize, accessibility: accessibility) == nil { return nil } } } - - private init(scope: ScopeOptions, publicTag: String, privateTag: String?) { + + private init(scope: ScopeOptions, publicTag: String, privateTag: String?, accessibility: KeypairAccessibility) { self.publicTag = publicTag self.privateTag = privateTag self.scope = scope + self.accessibility = accessibility + } // @@ -488,7 +491,7 @@ public class Heimdall { } if let privateTag = self.privateTag where self.destroy() { - if Heimdall.generateKeyPair(self.publicTag, privateTag: privateTag, keySize: keySize) != nil { + if Heimdall.generateKeyPair(self.publicTag, privateTag: privateTag, keySize: keySize, accessibility: accessibility) != nil { // Restore our scope back to .All self.scope = .All return true @@ -613,13 +616,14 @@ public class Heimdall { return SecItemDelete(query) == noErr } - private class func insertPublicKey(publicTag: String, data: NSData) -> SecKeyRef? { + private class func insertPublicKey(publicTag: String, accessibility: KeypairAccessibility, data: NSData) -> SecKeyRef? { var publicAttributes = Dictionary() publicAttributes[String(kSecAttrKeyType)] = kSecAttrKeyTypeRSA publicAttributes[String(kSecClass)] = kSecClassKey as CFStringRef publicAttributes[String(kSecAttrApplicationTag)] = publicTag as CFStringRef publicAttributes[String(kSecValueData)] = data as CFDataRef publicAttributes[String(kSecReturnPersistentRef)] = true as CFBooleanRef + publicAttributes[String(kSecAttrAccessible)] = accessibility.accessibilityConstant as CFStringRef var persistentRef: AnyObject? let status = SecItemAdd(publicAttributes, &persistentRef) @@ -632,7 +636,7 @@ public class Heimdall { } - private class func generateKeyPair(publicTag: String, privateTag: String, keySize: Int) -> (publicKey: SecKeyRef, privateKey: SecKeyRef)? { + private class func generateKeyPair(publicTag: String, privateTag: String, keySize: Int, accessibility: KeypairAccessibility) -> (publicKey: SecKeyRef, privateKey: SecKeyRef)? { let privateAttributes = [String(kSecAttrIsPermanent): true, String(kSecAttrApplicationTag): privateTag] let publicAttributes = [String(kSecAttrIsPermanent): true, @@ -641,7 +645,8 @@ public class Heimdall { let pairAttributes = [String(kSecAttrKeyType): kSecAttrKeyTypeRSA, String(kSecAttrKeySizeInBits): keySize, String(kSecPublicKeyAttrs): publicAttributes, - String(kSecPrivateKeyAttrs): privateAttributes] + String(kSecPrivateKeyAttrs): privateAttributes, + String(kSecAttrAccessible): accessibility.accessibilityConstant] var publicRef: SecKey? var privateRef: SecKey? @@ -735,6 +740,39 @@ public class Heimdall { } } +/// +/// Keychain Accessibility Constants +/// + +public enum KeypairAccessibility { + case AfterFirstUnlock + case AfterFirstUnlockThisDeviceOnly + case Always + case AlwaysThisDeviceOnly + case WhenPasscodeSetThisDeviceOnly + case WhenUnlocked + case WhenUnlockedThisDeviceOnly + + private var accessibilityConstant: String { + switch self { + case .AfterFirstUnlock: + return String(kSecAttrAccessibleAfterFirstUnlock) + case .AfterFirstUnlockThisDeviceOnly: + return String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) + case .Always: + return String(kSecAttrAccessibleAlways) + case .AlwaysThisDeviceOnly: + return String(kSecAttrAccessibleAlwaysThisDeviceOnly) + case .WhenPasscodeSetThisDeviceOnly: + return String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly) + case .WhenUnlocked: + return String(kSecAttrAccessibleWhenUnlocked) + case .WhenUnlockedThisDeviceOnly: + return String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly) + } + } +} + /// /// Arithmetic /// From 5365d4f79b6f61725e5b037df7e558108c3ddc5b Mon Sep 17 00:00:00 2001 From: Colin Morelli Date: Sun, 10 Jul 2016 00:24:47 -0400 Subject: [PATCH 2/6] Fixing indentation issues --- Heimdall/Heimdall.swift | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Heimdall/Heimdall.swift b/Heimdall/Heimdall.swift index cbad2e2..2b4c8f5 100644 --- a/Heimdall/Heimdall.swift +++ b/Heimdall/Heimdall.swift @@ -55,21 +55,21 @@ public class Heimdall { /// - returns: Heimdall instance that can handle only public key operations /// public convenience init?(publicTag: String, publicKeyData: NSData? = nil, accessibility: KeypairAccessibility = .WhenUnlocked) { - if let existingData = Heimdall.obtainKeyData(publicTag) { - // Compare agains the new data (optional) - if let newData = publicKeyData?.dataByStrippingX509Header() where !existingData.isEqualToData(newData) { - Heimdall.updateKey(publicTag, data: newData) + if let existingData = Heimdall.obtainKeyData(publicTag) { + // Compare agains the new data (optional) + if let newData = publicKeyData?.dataByStrippingX509Header() where !existingData.isEqualToData(newData) { + Heimdall.updateKey(publicTag, data: newData) + } + + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) + } else if let data = publicKeyData?.dataByStrippingX509Header(), _ = Heimdall.insertPublicKey(publicTag, accessibility: accessibility, data: data) { + // Successfully created the new key + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) + } else { + // Call the init, although returning nil + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) + return nil } - - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) - } else if let data = publicKeyData?.dataByStrippingX509Header(), _ = Heimdall.insertPublicKey(publicTag, accessibility: accessibility, data: data) { - // Successfully created the new key - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) - } else { - // Call the init, although returning nil - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) - return nil - } } /// From 05a509b35113bd010f9630559e998849c76e4426 Mon Sep 17 00:00:00 2001 From: Colin Morelli Date: Sun, 10 Jul 2016 00:26:11 -0400 Subject: [PATCH 3/6] Fixing more indentation issues --- Heimdall/Heimdall.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heimdall/Heimdall.swift b/Heimdall/Heimdall.swift index 2b4c8f5..f1a1a4a 100644 --- a/Heimdall/Heimdall.swift +++ b/Heimdall/Heimdall.swift @@ -623,7 +623,7 @@ public class Heimdall { publicAttributes[String(kSecAttrApplicationTag)] = publicTag as CFStringRef publicAttributes[String(kSecValueData)] = data as CFDataRef publicAttributes[String(kSecReturnPersistentRef)] = true as CFBooleanRef - publicAttributes[String(kSecAttrAccessible)] = accessibility.accessibilityConstant as CFStringRef + publicAttributes[String(kSecAttrAccessible)] = accessibility.accessibilityConstant as CFStringRef var persistentRef: AnyObject? let status = SecItemAdd(publicAttributes, &persistentRef) From 103515f7ed269ddf7adc261a4a2c367d09f7c635 Mon Sep 17 00:00:00 2001 From: Colin Morelli Date: Sun, 10 Jul 2016 00:28:01 -0400 Subject: [PATCH 4/6] Fixing constructor call --- Heimdall/Heimdall.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heimdall/Heimdall.swift b/Heimdall/Heimdall.swift index f1a1a4a..0bde619 100644 --- a/Heimdall/Heimdall.swift +++ b/Heimdall/Heimdall.swift @@ -100,7 +100,7 @@ public class Heimdall { /// - returns: Heimdall instance that can handle both private and public key operations /// public convenience init?(tagPrefix: String, keySize: Int = 2048, accessibility: KeypairAccessibility = .WhenUnlocked) { - self.init(publicTag: tagPrefix, privateTag: tagPrefix + ".private", keySize: keySize) + self.init(publicTag: tagPrefix, privateTag: tagPrefix + ".private", keySize: keySize, accessibility: accessibility) } /// From f8d8efbecffc935de8a3feeb37c8326d7955961d Mon Sep 17 00:00:00 2001 From: Henri Normak Date: Sat, 11 Feb 2017 13:10:02 +0200 Subject: [PATCH 5/6] Fix documentation, refactor keychain access related code Renamed the access related code, to reduce confusion with accessibility related features in iOS/Keychain. Also, made sure the access related code is appropriately used (for example, there is no real need to store the value, as it is not used at all). --- Heimdall/Heimdall.swift | 68 +++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/Heimdall/Heimdall.swift b/Heimdall/Heimdall.swift index 316f13c..ae9fbb6 100644 --- a/Heimdall/Heimdall.swift +++ b/Heimdall/Heimdall.swift @@ -42,7 +42,6 @@ open class Heimdall { fileprivate let publicTag: String fileprivate var privateTag: String? fileprivate var scope: ScopeOptions - private var accessibility: KeypairAccess /// /// Create an instance with data for the public key, @@ -52,26 +51,27 @@ open class Heimdall { /// - publicTag: Tag of the public key, keychain is checked for existing key (updated if data /// provided is non-nil and does not match) /// - publicKeyData: Bits of the public key, can include the X509 header (will be stripped) + /// - access: When the underlying key pair can be read from the device's Keychain /// /// - returns: Heimdall instance that can handle only public key operations /// - public convenience init?(publicTag: String, publicKeyData: Data? = nil, accessibility: KeypairAccess = .WhenUnlocked) { + public convenience init?(publicTag: String, publicKeyData: Data? = nil, access: KeypairAccess = .WhenUnlocked) { if let existingData = Heimdall.obtainKeyData(publicTag) { - // Compare agains the new data (optional) + // Compare against the new data (optional) if let newData = publicKeyData?.dataByStrippingX509Header() , (existingData != newData) { - if !Heimdall.updateKey(publicTag, data: newData) { + if !Heimdall.updateKey(publicTag, data: newData, access: access) { // Failed to update the key, fail the initialisation return nil } } - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) - } else if let data = publicKeyData?.dataByStrippingX509Header(), let _ = Heimdall.insertPublicKey(publicTag, data: data, accessibility: accessibility) { + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil) + } else if let data = publicKeyData?.dataByStrippingX509Header(), let _ = Heimdall.insertPublicKey(publicTag, data: data, access: access) { // Successfully created the new key - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil) } else { // Call the init, although returning nil - self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil, accessibility: accessibility) + self.init(scope: ScopeOptions.PublicKey, publicTag: publicTag, privateTag: nil) return nil } } @@ -84,13 +84,14 @@ open class Heimdall { /// - publicTag: Tag of the public key, see data based initialiser for details /// - publicKeyModulus: Modulus of the public key /// - publicKeyExponent: Exponent of the public key + /// - access: When the underlying key pair can be read from the device's Keychain /// /// - returns: Heimdall instance that can handle only public key operations /// - public convenience init?(publicTag: String, publicKeyModulus: Data, publicKeyExponent: Data, accessibility: KeypairAccess = .WhenUnlocked) { + public convenience init?(publicTag: String, publicKeyModulus: Data, publicKeyExponent: Data, access: KeypairAccess = .WhenUnlocked) { // Combine the data into one that we can use for initialisation let combinedData = Data(modulus: publicKeyModulus, exponent: publicKeyExponent) - self.init(publicTag: publicTag, publicKeyData: combinedData, accessibility: accessibility) + self.init(publicTag: publicTag, publicKeyData: combinedData, access: access) } /// @@ -100,11 +101,12 @@ open class Heimdall { /// - parameters /// - tagPrefix: Prefix to use for the private/public keys in Keychain /// - keySize: Size of the RSA key pair (in bits) + /// - access: When the underlying key pair can be read from the device's Keychain /// /// - returns: Heimdall instance that can handle both private and public key operations /// - public convenience init?(tagPrefix: String, keySize: Int = 2048, accessibility: KeypairAccess = .WhenUnlocked) { - self.init(publicTag: tagPrefix, privateTag: tagPrefix + ".private", keySize: keySize, accessibility: accessibility) + public convenience init?(tagPrefix: String, keySize: Int = 2048, access: KeypairAccess = .WhenUnlocked) { + self.init(publicTag: tagPrefix, privateTag: tagPrefix + ".private", keySize: keySize, access: access) } /// @@ -115,24 +117,24 @@ open class Heimdall { /// - publicTag: Tag to use for the public key /// - privateTag: Tag to use for the private key /// - keySize: Size of the RSA key pair (in bits) + /// - access: When the underlying key pair can be read from the device's Keychain /// /// - returns: Heimdall instance ready for both public and private key operations /// - public convenience init?(publicTag: String, privateTag: String, keySize: Int = 2048, accessibility: KeypairAccess = .WhenUnlocked) { - self.init(scope: ScopeOptions.All, publicTag: publicTag, privateTag: privateTag, accessibility: accessibility) + public convenience init?(publicTag: String, privateTag: String, keySize: Int = 2048, access: KeypairAccess = .WhenUnlocked) { + self.init(scope: ScopeOptions.All, publicTag: publicTag, privateTag: privateTag) if Heimdall.obtainKey(publicTag) == nil || Heimdall.obtainKey(privateTag) == nil { - if Heimdall.generateKeyPair(publicTag, privateTag: privateTag, keySize: keySize, accessibility: accessibility) == nil { + if Heimdall.generateKeyPair(publicTag, privateTag: privateTag, keySize: keySize, access: access) == nil { return nil } } } - fileprivate init(scope: ScopeOptions, publicTag: String, privateTag: String?, accessibility: KeypairAccess) { + fileprivate init(scope: ScopeOptions, publicTag: String, privateTag: String?) { self.publicTag = publicTag self.privateTag = privateTag self.scope = scope - self.accessibility = accessibility } // @@ -489,17 +491,18 @@ open class Heimdall { /// /// - parameters: /// - keySize: Size of keys in the new pair + /// - access: When the underlying key pair can be read from the device's Keychain /// /// - returns: True if reset successfully /// - @discardableResult open func regenerate(_ keySize: Int = 2048) -> Bool { + @discardableResult open func regenerate(keySize: Int = 2048, access: KeypairAccess = .WhenUnlocked) -> Bool { // Only if we currently have a private key in our control (or we think we have one) if self.scope & ScopeOptions.PrivateKey != ScopeOptions.PrivateKey { return false } if let privateTag = self.privateTag, self.destroy() { - if Heimdall.generateKeyPair(self.publicTag, privateTag: privateTag, keySize: keySize, accessibility: accessibility) != nil { + if Heimdall.generateKeyPair(self.publicTag, privateTag: privateTag, keySize: keySize, access: access) != nil { // Restore our scope back to .All self.scope = .All return true @@ -606,14 +609,27 @@ open class Heimdall { return result } - fileprivate class func updateKey(_ tag: String, data: Data) -> Bool { + fileprivate class func updateKey(_ tag: String, data: Data? = nil, access: KeypairAccess? = nil) -> Bool { let query: Dictionary = [ String(kSecAttrKeyType): kSecAttrKeyTypeRSA, String(kSecClass): kSecClassKey as CFString, String(kSecAttrApplicationTag): tag as CFString] + guard data != nil || access != nil else { + return true + } + + var update = Dictionary() + + if let data = data { + update[String(kSecValueData)] = data + } + + if let access = access { + update[String(kSecAttrAccessible)] = access.securityConstant as CFString + } - return SecItemUpdate(query as CFDictionary, [String(kSecValueData): data] as CFDictionary) == noErr + return SecItemUpdate(query as CFDictionary, update as CFDictionary) == noErr } fileprivate class func deleteKey(_ tag: String) -> Bool { @@ -625,14 +641,14 @@ open class Heimdall { return SecItemDelete(query as CFDictionary) == noErr } - fileprivate class func insertPublicKey(_ publicTag: String, data: Data, accessibility: KeypairAccess) -> SecKey? { + fileprivate class func insertPublicKey(_ publicTag: String, data: Data, access: KeypairAccess) -> SecKey? { var publicAttributes = Dictionary() publicAttributes[String(kSecAttrKeyType)] = kSecAttrKeyTypeRSA publicAttributes[String(kSecClass)] = kSecClassKey as CFString publicAttributes[String(kSecAttrApplicationTag)] = publicTag as CFString publicAttributes[String(kSecValueData)] = data as CFData publicAttributes[String(kSecReturnPersistentRef)] = true as CFBoolean - publicAttributes[String(kSecAttrAccessible)] = accessibility.accessConstant as CFString + publicAttributes[String(kSecAttrAccessible)] = access.securityConstant as CFString var persistentRef: AnyObject? let status = SecItemAdd(publicAttributes as CFDictionary, &persistentRef) @@ -644,7 +660,7 @@ open class Heimdall { return Heimdall.obtainKey(publicTag) } - fileprivate class func generateKeyPair(_ publicTag: String, privateTag: String, keySize: Int, accessibility: KeypairAccess) -> (publicKey: SecKey, privateKey: SecKey)? { + fileprivate class func generateKeyPair(_ publicTag: String, privateTag: String, keySize: Int, access: KeypairAccess) -> (publicKey: SecKey, privateKey: SecKey)? { let privateAttributes = [String(kSecAttrIsPermanent): true, String(kSecAttrApplicationTag): privateTag] as [String : Any] let publicAttributes = [String(kSecAttrIsPermanent): true, @@ -654,7 +670,7 @@ open class Heimdall { String(kSecAttrKeySizeInBits): keySize, String(kSecPublicKeyAttrs): publicAttributes, String(kSecPrivateKeyAttrs): privateAttributes, - String(kSecAttrAccessible): accessibility.accessConstant] as [String : Any] + String(kSecAttrAccessible): access.securityConstant] as [String : Any] var publicRef: SecKey? var privateRef: SecKey? @@ -764,7 +780,7 @@ public enum KeypairAccess { case WhenUnlocked case WhenUnlockedThisDeviceOnly - fileprivate var accessConstant: String { + fileprivate var securityConstant: String { switch self { case .AfterFirstUnlock: return String(kSecAttrAccessibleAfterFirstUnlock) From ecf76d8d48b18d062603a16a381dab558b40f982 Mon Sep 17 00:00:00 2001 From: Henri Normak Date: Sat, 11 Feb 2017 13:11:20 +0200 Subject: [PATCH 6/6] Allow labelless keySize in regenerate call --- Heimdall/Heimdall.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heimdall/Heimdall.swift b/Heimdall/Heimdall.swift index ae9fbb6..43efb65 100644 --- a/Heimdall/Heimdall.swift +++ b/Heimdall/Heimdall.swift @@ -495,7 +495,7 @@ open class Heimdall { /// /// - returns: True if reset successfully /// - @discardableResult open func regenerate(keySize: Int = 2048, access: KeypairAccess = .WhenUnlocked) -> Bool { + @discardableResult open func regenerate(_ keySize: Int = 2048, access: KeypairAccess = .WhenUnlocked) -> Bool { // Only if we currently have a private key in our control (or we think we have one) if self.scope & ScopeOptions.PrivateKey != ScopeOptions.PrivateKey { return false