Skip to content
This repository has been archived by the owner on Aug 24, 2019. It is now read-only.

Support Biometry #193

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
24 changes: 24 additions & 0 deletions SAMKeychain.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@
21632DD31C9282BD00C40D7D /* KeychainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21632DD21C9282BD00C40D7D /* KeychainTests.swift */; };
21632DD41C9282BD00C40D7D /* KeychainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21632DD21C9282BD00C40D7D /* KeychainTests.swift */; };
21632DD51C9282BD00C40D7D /* KeychainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21632DD21C9282BD00C40D7D /* KeychainTests.swift */; };
C598E1962086415500B79528 /* SAMKeychainAccessControl.h in Headers */ = {isa = PBXBuildFile; fileRef = C598E1942086415500B79528 /* SAMKeychainAccessControl.h */; };
C598E1972086415500B79528 /* SAMKeychainAccessControl.h in Headers */ = {isa = PBXBuildFile; fileRef = C598E1942086415500B79528 /* SAMKeychainAccessControl.h */; };
C598E1982086415500B79528 /* SAMKeychainAccessControl.h in Headers */ = {isa = PBXBuildFile; fileRef = C598E1942086415500B79528 /* SAMKeychainAccessControl.h */; };
C598E1992086415500B79528 /* SAMKeychainAccessControl.h in Headers */ = {isa = PBXBuildFile; fileRef = C598E1942086415500B79528 /* SAMKeychainAccessControl.h */; };
C598E19A2086415500B79528 /* SAMKeychainAccessControl.m in Sources */ = {isa = PBXBuildFile; fileRef = C598E1952086415500B79528 /* SAMKeychainAccessControl.m */; };
C598E19B2086415500B79528 /* SAMKeychainAccessControl.m in Sources */ = {isa = PBXBuildFile; fileRef = C598E1952086415500B79528 /* SAMKeychainAccessControl.m */; };
C598E19C2086415500B79528 /* SAMKeychainAccessControl.m in Sources */ = {isa = PBXBuildFile; fileRef = C598E1952086415500B79528 /* SAMKeychainAccessControl.m */; };
C598E19D2086415500B79528 /* SAMKeychainAccessControl.m in Sources */ = {isa = PBXBuildFile; fileRef = C598E1952086415500B79528 /* SAMKeychainAccessControl.m */; };
C5AF91D4208AC10C00136637 /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C5AF91D3208AC10C00136637 /* LocalAuthentication.framework */; };
E8A6665B1A844D3A00287CA3 /* SAMKeychain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8A666341A844CC400287CA3 /* SAMKeychain.framework */; };
E8A6667A1A844E4100287CA3 /* SAMKeychain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8A6666F1A844E4100287CA3 /* SAMKeychain.framework */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -82,6 +91,9 @@
21CC42AE17DB874300201DDC /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
21CC42C317DB874300201DDC /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
21CC42F917DB87C300201DDC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
C598E1942086415500B79528 /* SAMKeychainAccessControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAMKeychainAccessControl.h; sourceTree = "<group>"; };
C598E1952086415500B79528 /* SAMKeychainAccessControl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAMKeychainAccessControl.m; sourceTree = "<group>"; };
C5AF91D3208AC10C00136637 /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = System/Library/Frameworks/LocalAuthentication.framework; sourceTree = SDKROOT; };
E8A666341A844CC400287CA3 /* SAMKeychain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SAMKeychain.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E8A666551A844D3A00287CA3 /* SAMKeychainTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SAMKeychainTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
E8A6666F1A844E4100287CA3 /* SAMKeychain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SAMKeychain.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -115,6 +127,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C5AF91D4208AC10C00136637 /* LocalAuthentication.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -151,6 +164,8 @@
21632D7D1C92599100C40D7D /* SAMKeychain.m */,
21632D7E1C92599100C40D7D /* SAMKeychainQuery.h */,
21632D7F1C92599100C40D7D /* SAMKeychainQuery.m */,
C598E1942086415500B79528 /* SAMKeychainAccessControl.h */,
C598E1952086415500B79528 /* SAMKeychainAccessControl.m */,
);
path = Sources;
sourceTree = "<group>";
Expand Down Expand Up @@ -204,6 +219,7 @@
21CC42A917DB874300201DDC /* Frameworks */ = {
isa = PBXGroup;
children = (
C5AF91D3208AC10C00136637 /* LocalAuthentication.framework */,
21B85B6E18EC963A009D2B98 /* Cocoa.framework */,
21B85B1E18EC9391009D2B98 /* Security.framework */,
21CC42F917DB87C300201DDC /* Security.framework */,
Expand Down Expand Up @@ -232,6 +248,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
C598E1982086415500B79528 /* SAMKeychainAccessControl.h in Headers */,
21632DB11C925A6000C40D7D /* SAMKeychain.h in Headers */,
21632DB31C925A6000C40D7D /* SAMKeychainQuery.h in Headers */,
);
Expand All @@ -241,6 +258,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
C598E1992086415500B79528 /* SAMKeychainAccessControl.h in Headers */,
21632DC51C925B3700C40D7D /* SAMKeychain.h in Headers */,
21632DC71C925B3700C40D7D /* SAMKeychainQuery.h in Headers */,
);
Expand All @@ -250,6 +268,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
C598E1962086415500B79528 /* SAMKeychainAccessControl.h in Headers */,
21632D821C92599100C40D7D /* SAMKeychain.h in Headers */,
21632D841C92599100C40D7D /* SAMKeychainQuery.h in Headers */,
);
Expand All @@ -259,6 +278,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
C598E1972086415500B79528 /* SAMKeychainAccessControl.h in Headers */,
21632D8F1C9259C100C40D7D /* SAMKeychain.h in Headers */,
21632D911C9259C100C40D7D /* SAMKeychainQuery.h in Headers */,
);
Expand Down Expand Up @@ -505,6 +525,7 @@
buildActionMask = 2147483647;
files = (
21632DB41C925A6000C40D7D /* SAMKeychainQuery.m in Sources */,
C598E19C2086415500B79528 /* SAMKeychainAccessControl.m in Sources */,
21632DB21C925A6000C40D7D /* SAMKeychain.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -522,6 +543,7 @@
buildActionMask = 2147483647;
files = (
21632DC81C925B3700C40D7D /* SAMKeychainQuery.m in Sources */,
C598E19D2086415500B79528 /* SAMKeychainAccessControl.m in Sources */,
21632DC61C925B3700C40D7D /* SAMKeychain.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -531,6 +553,7 @@
buildActionMask = 2147483647;
files = (
21632D851C92599100C40D7D /* SAMKeychainQuery.m in Sources */,
C598E19A2086415500B79528 /* SAMKeychainAccessControl.m in Sources */,
21632D831C92599100C40D7D /* SAMKeychain.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -548,6 +571,7 @@
buildActionMask = 2147483647;
files = (
21632D921C9259C100C40D7D /* SAMKeychainQuery.m in Sources */,
C598E19B2086415500B79528 /* SAMKeychainAccessControl.m in Sources */,
21632D901C9259C100C40D7D /* SAMKeychain.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
94 changes: 94 additions & 0 deletions Sources/SAMKeychainAccessControl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//
// SAMKeychainAccessControl.h
// SAMKeychain
//
// Created by Liam Nichols on 01/09/2014.
// Copyright (c) 2014 Sam Soffes. All rights reserved.
//

@import Foundation;
@import Security;

/** kSecAttrAccessible */
typedef NS_ENUM(NSUInteger, SAMKeychainAccessibility) {
/** kSecAttrAccessibleWhenUnlocked */
SAMKeychainAccessibilityWhenUnlocked = 1,

/** kSecAttrAccessibleAfterFirstUnlock */
SAMKeychainAccessibilityAfterFirstUnlock,

/** kSecAttrAccessibleAlways */
SAMKeychainAccessibilityAlways,

/** kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly */
SAMKeychainAccessibilityWhenPasscodeSetThisDeviceOnly,

/** kSecAttrAccessibleWhenUnlockedThisDeviceOnly */
SAMKeychainAccessibilityWhenUnlockedThisDeviceOnly,

/** kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly */
SAMKeychainAccessibilityAfterFirstUnlockThisDeviceOnly,

/** kSecAttrAccessibleAlwaysThisDeviceOnly */
SAMKeychainAccessibilityAlwaysThisDeviceOnly
};

/** SecAccessControlCreateFlags */
typedef NS_OPTIONS(NSUInteger, SAMKeychainCreateFlags) {
/** kSecAccessControlUserPresence
User presence policy using biometry or Passcode. Biometry does not have to be available or 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.
*/
SAMKeychainCreateFlagUserPresence = 1u << 0,

/** kSecAccessControlBiometryAny
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.
*/
SAMKeychainCreateFlagBiometryAny CF_ENUM_AVAILABLE(10_12_1, 9_0) = 1u << 1,

/** kSecAccessControlBiometryCurrentSet
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.
*/
SAMKeychainCreateFlagBiometryCurrentSet CF_ENUM_AVAILABLE(10_12_1, 9_0) = 1u << 3,

/** kSecAccessControlDevicePasscode
Constraint: Device passcode
*/
SAMKeychainCreateFlagDevicePasscode CF_ENUM_AVAILABLE(10_11, 9_0) = 1u << 4,

/** kSecAccessControlOr
Constraint logic operation: when using more than one constraint, at least one of them must be satisfied.
*/
SAMKeychainCreateFlagOr CF_ENUM_AVAILABLE(10_12_1, 9_0) = 1u << 14,

/** kSecAccessControlAnd
Constraint logic operation: when using more than one constraint, all must be satisfied.
*/
SAMKeychainCreateFlagAnd CF_ENUM_AVAILABLE(10_12_1, 9_0) = 1u << 15,

/** kSecAccessControlPrivateKeyUsage
Create access control for private key operations (i.e. sign operation)
*/
SAMKeychainCreateFlagPrivateKeyUsage CF_ENUM_AVAILABLE(10_12_1, 9_0) = 1u << 30,

/** kSecAccessControlApplicationPassword
Security: Application provided password for data encryption key generation. This is not a constraint but additional item
encryption mechanism.
*/
SAMKeychainCreateFlagApplicationPassword CF_ENUM_AVAILABLE(10_12_1, 9_0) = 1u << 31,
} __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0);

extern CFTypeRef getSecAttrAccessibility(SAMKeychainAccessibility ssAttr);

@interface SAMKeychainAccessControl : NSObject

+ (instancetype)accessControlWithAccessibility:(SAMKeychainAccessibility)accesibility flags:(SAMKeychainCreateFlags)flags;

@property (nonatomic, assign) SAMKeychainAccessibility accessibility;

@property (nonatomic, assign) SAMKeychainCreateFlags flags;

@end
33 changes: 33 additions & 0 deletions Sources/SAMKeychainAccessControl.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// SAMKeychainAccessControl.m
// SAMKeychain
//
// Created by Liam Nichols on 01/09/2014.
// Copyright (c) 2014 Sam Soffes. All rights reserved.
//

#import "SAMKeychainAccessControl.h"

@implementation SAMKeychainAccessControl

+ (instancetype)accessControlWithAccessibility:(SAMKeychainAccessibility)accesibility flags:(SAMKeychainCreateFlags)flags {
SAMKeychainAccessControl *accessControl = [self new];
accessControl.accessibility = accesibility;
accessControl.flags = flags;
return accessControl;
}

@end

CFTypeRef getSecAttrAccessibility(SAMKeychainAccessibility ssAttr) {
switch (ssAttr) {
case SAMKeychainAccessibilityAlways: return kSecAttrAccessibleAlways;
case SAMKeychainAccessibilityWhenUnlocked: return kSecAttrAccessibleWhenUnlocked;
case SAMKeychainAccessibilityAfterFirstUnlock: return kSecAttrAccessibleAfterFirstUnlock;
case SAMKeychainAccessibilityAlwaysThisDeviceOnly: return kSecAttrAccessibleAlwaysThisDeviceOnly;
case SAMKeychainAccessibilityWhenUnlockedThisDeviceOnly: return kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
case SAMKeychainAccessibilityWhenPasscodeSetThisDeviceOnly: return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;
case SAMKeychainAccessibilityAfterFirstUnlockThisDeviceOnly: return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;
default: return NULL;
}
}
70 changes: 68 additions & 2 deletions Sources/SAMKeychainQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@
#import <Security/Security.h>
#endif

#if __IPHONE_8_0 || __MAC_10_10
#define SAMKEYCHAIN_ACCESS_CONTROL_AVAILABLE 1
#endif

#ifdef SAMKEYCHAIN_ACCESS_CONTROL_AVAILABLE
#import <SAMKeychain/SAMKeychainAccessControl.h>
#endif

NS_ASSUME_NONNULL_BEGIN

#if __IPHONE_7_0 || __MAC_10_9
Expand Down Expand Up @@ -58,6 +66,23 @@ typedef NS_ENUM(NSUInteger, SAMKeychainQuerySynchronizationMode) {
@property (nonatomic) SAMKeychainQuerySynchronizationMode synchronizationMode;
#endif

#if __IPHONE_8_0 && TARGET_OS_IPHONE
/** kSecUseOperationPrompt */
@property (nonatomic, copy) NSString *useOperationPrompt;

/** kSecUseNoAuthenticationUI */
@property (nonatomic, assign) NSNumber *useNoAuthenticationUI DEPRECATED_MSG_ATTRIBUTE("Use -useAuthenticationUI instead.");

/** kSecUseAuthenticationUI */
@property (nonatomic, assign) NSNumber *useAuthenticationUI;
#endif

#if SAMKEYCHAIN_ACCESS_CONTROL_AVAILABLE
/** kSecAttrAccessControl */
@property (nonatomic, strong) SAMKeychainAccessControl *accessControl;
#endif


/** Root storage for password information */
@property (nonatomic, copy, nullable) NSData *passwordData;

Expand All @@ -75,7 +100,7 @@ typedef NS_ENUM(NSUInteger, SAMKeychainQuerySynchronizationMode) {


///------------------------
/// @name Saving & Deleting
/// @name Saving, Updating & Deleting
///------------------------

/**
Expand All @@ -88,6 +113,15 @@ typedef NS_ENUM(NSUInteger, SAMKeychainQuerySynchronizationMode) {
*/
- (BOOL)save:(NSError **)error;

/**
Updates the receiver's attributes.

@param error Populated should an error occur.

@return `YES` if saving was successful, `NO` otherwise.
*/
- (BOOL)update:(NSError **)error;

/**
Delete keychain items that match the given account, service, and access group.

Expand Down Expand Up @@ -133,7 +167,7 @@ typedef NS_ENUM(NSUInteger, SAMKeychainQuerySynchronizationMode) {

#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE
/**
Returns a boolean indicating if keychain synchronization is available on the device at runtime. The #define
Returns a boolean indicating if keychain synchronization is available on the device at runtime. The #define
SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE is only for compile time. If you are checking for the presence of synchronization,
you should use this method.

Expand All @@ -142,6 +176,38 @@ typedef NS_ENUM(NSUInteger, SAMKeychainQuerySynchronizationMode) {
+ (BOOL)isSynchronizationAvailable;
#endif


///-----------------------------
/// @name Access Control Status
///-----------------------------

#ifdef SAMKEYCHAIN_ACCESS_CONTROL_AVAILABLE
/**
Returns a boolean indicating if keychain access control is available on the device at runtime. The #define
SAMKEYCHAIN_ACCESS_CONTROL_AVAILABLE is only for compile time. If you are checking for the presence of access control,
you should use this method.

@return A value indicating if keychain access control is available
*/
+ (BOOL)isAccessControlAvailable;

#if TARGET_OS_IPHONE
/**
Returns a boolean indicating if biometry is configured on the device.

@return A value indicating if authentication by biometry is configured
*/
+ (BOOL)isBiometryAvailable;

/**
Returns a boolean indicating if device passcode or biometry is configured on the device.

@return A value indicating if device passcode or biometry is configured
*/
+ (BOOL)isPasscodeOrBiometryAvailable;
#endif
#endif

@end

NS_ASSUME_NONNULL_END
Loading