Skip to content
This repository was archived by the owner on Aug 24, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Example/iOS/SSAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
//

#import "SSAppDelegate.h"
#import "SSKeychain.h"

@implementation SSAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
Expand Down
18 changes: 18 additions & 0 deletions SSKeychain.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
21DB72BA18ECA0BB00531E87 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 21DB72B518ECA0BB00531E87 /* main.m */; };
21DB72BB18ECA0BB00531E87 /* SSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 21DB72B718ECA0BB00531E87 /* SSAppDelegate.m */; };
21F116AC18EC9E6400126982 /* SSKeychainMac.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = 21F116AB18EC9E6400126982 /* SSKeychainMac.entitlements */; };
5361F5F519B4E71E005E92AD /* SSKeychainAccessControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 5361F5F419B4E71E005E92AD /* SSKeychainAccessControl.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -90,6 +91,8 @@
21DB72B718ECA0BB00531E87 /* SSAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSAppDelegate.m; sourceTree = "<group>"; };
21DB72B818ECA0BB00531E87 /* SSKeychain-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SSKeychain-Info.plist"; sourceTree = "<group>"; };
21F116AB18EC9E6400126982 /* SSKeychainMac.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = SSKeychainMac.entitlements; sourceTree = "<group>"; };
5361F5F319B4E71E005E92AD /* SSKeychainAccessControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKeychainAccessControl.h; sourceTree = "<group>"; };
5361F5F419B4E71E005E92AD /* SSKeychainAccessControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKeychainAccessControl.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -224,6 +227,8 @@
21CC42F017DB878300201DDC /* SSKeychain.m */,
21CC42F117DB878300201DDC /* SSKeychainQuery.h */,
21CC42F217DB878300201DDC /* SSKeychainQuery.m */,
5361F5F319B4E71E005E92AD /* SSKeychainAccessControl.h */,
5361F5F419B4E71E005E92AD /* SSKeychainAccessControl.m */,
);
path = SSKeychain;
sourceTree = "<group>";
Expand Down Expand Up @@ -333,6 +338,9 @@
21B85B4218EC9456009D2B98 = {
TestTargetID = 21CC42A617DB874300201DDC;
};
21CC42A617DB874300201DDC = {
DevelopmentTeam = RPD4MEV338;
};
21CC42C117DB874300201DDC = {
TestTargetID = 21CC42A617DB874300201DDC;
};
Expand Down Expand Up @@ -421,6 +429,7 @@
buildActionMask = 2147483647;
files = (
21DB72BB18ECA0BB00531E87 /* SSAppDelegate.m in Sources */,
5361F5F519B4E71E005E92AD /* SSKeychainAccessControl.m in Sources */,
21CC42F717DB878300201DDC /* SSKeychainQuery.m in Sources */,
21DB72BA18ECA0BB00531E87 /* main.m in Sources */,
21CC42F517DB878300201DDC /* SSKeychain.m in Sources */,
Expand Down Expand Up @@ -515,8 +524,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
INFOPLIST_FILE = "$(SRCROOT)/Example/iOS/SSKeychain-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
WRAPPER_EXTENSION = app;
};
name = Test;
Expand Down Expand Up @@ -759,8 +771,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
INFOPLIST_FILE = "$(SRCROOT)/Example/iOS/SSKeychain-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
WRAPPER_EXTENSION = app;
};
name = Debug;
Expand All @@ -770,8 +785,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
INFOPLIST_FILE = "$(SRCROOT)/Example/iOS/SSKeychain-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
WRAPPER_EXTENSION = app;
};
name = Release;
Expand Down
51 changes: 51 additions & 0 deletions SSKeychain/SSKeychainAccessControl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// SSKeychainAccessControl.h
// SSKeychain
//
// Created by Liam Nichols on 01/09/2014.
// Copyright (c) 2014 Sam Soffes. All rights reserved.
//

#import <Foundation/Foundation.h>

/** kSecAttrAccessible */
typedef NS_ENUM(NSUInteger, SSKeychainAccessibility) {
/** kSecAttrAccessibleWhenUnlocked */
SSKeychainAccessibilityWhenUnlocked = 1,

/** kSecAttrAccessibleAfterFirstUnlock */
SSKeychainAccessibilityAfterFirstUnlock,

/** kSecAttrAccessibleAlways */
SSKeychainAccessibilityAlways,

/** kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly */
SSKeychainAccessibilityWhenPasscodeSetThisDeviceOnly,

/** kSecAttrAccessibleWhenUnlockedThisDeviceOnly */
SSKeychainAccessibilityWhenUnlockedThisDeviceOnly,

/** kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly */
SSKeychainAccessibilityAfterFisrtUnlockThisDeviceOnly,

/** kSecAttrAccessibleAlwaysThisDeviceOnly */
SSKeychainAccessibilityAlwaysThisDeviceOnly
};

/** SecAccessControlCreateFlags */
typedef NS_OPTIONS(NSUInteger, SSKeychainCreateFlags) {
/** kSecAccessControlUserPresence */
SSKeychainCreateFlagUserPresence = 1UL << 0
};

extern CFTypeRef getSecAttrAccessibility(SSKeychainAccessibility ssAttr);

@interface SSKeychainAccessControl : NSObject

+ (instancetype)accessControlWithAccessibility:(SSKeychainAccessibility)accesibility flags:(SSKeychainCreateFlags)flags;

@property (nonatomic, assign) SSKeychainAccessibility accessibility;

@property (nonatomic, assign) SSKeychainCreateFlags flags;

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

#import "SSKeychainAccessControl.h"

@implementation SSKeychainAccessControl

+ (instancetype)accessControlWithAccessibility:(SSKeychainAccessibility)accesibility flags:(SSKeychainCreateFlags)flags
{
SSKeychainAccessControl *accessControl = [self new];
accessControl.accessibility = accesibility;
accessControl.flags = flags;
return accessControl;
}

@end

CFTypeRef getSecAttrAccessibility(SSKeychainAccessibility ssAttr)
{
switch (ssAttr) {
case SSKeychainAccessibilityAlways:
return kSecAttrAccessibleAlways;

case SSKeychainAccessibilityWhenUnlocked:
return kSecAttrAccessibleWhenUnlocked;

case SSKeychainAccessibilityAfterFirstUnlock:
return kSecAttrAccessibleAfterFirstUnlock;

case SSKeychainAccessibilityAlwaysThisDeviceOnly:
return kSecAttrAccessibleAlwaysThisDeviceOnly;

case SSKeychainAccessibilityWhenUnlockedThisDeviceOnly:
return kSecAttrAccessibleWhenUnlockedThisDeviceOnly;

case SSKeychainAccessibilityWhenPasscodeSetThisDeviceOnly:
return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;

case SSKeychainAccessibilityAfterFisrtUnlockThisDeviceOnly:
return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;

default:
return NULL;
}
}
26 changes: 25 additions & 1 deletion SSKeychain/SSKeychainQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#import <Foundation/Foundation.h>
#import <Security/Security.h>

#if __IPHONE_8_0 || __MAC_10_10
#import "SSKeychainAccessControl.h"
#endif

#if __IPHONE_7_0 || __MAC_10_9
// Keychain synchronization available at compile time
#define SSKEYCHAIN_SYNCHRONIZATION_AVAILABLE 1
Expand Down Expand Up @@ -46,6 +50,17 @@ typedef NS_ENUM(NSUInteger, SSKeychainQuerySynchronizationMode) {
@property (nonatomic) SSKeychainQuerySynchronizationMode synchronizationMode;
#endif

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

/** kSecUseNoAuthenticationUI */
@property (nonatomic, assign) NSNumber *useNoAuthenticationUI;

/** kSecAttrAccessControl */
@property (nonatomic, strong) SSKeychainAccessControl *accessControl;
#endif

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

Expand All @@ -63,7 +78,7 @@ typedef NS_ENUM(NSUInteger, SSKeychainQuerySynchronizationMode) {


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

/**
Expand All @@ -76,6 +91,15 @@ typedef NS_ENUM(NSUInteger, SSKeychainQuerySynchronizationMode) {
*/
- (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
76 changes: 76 additions & 0 deletions SSKeychain/SSKeychainQuery.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,31 @@ - (BOOL)save:(NSError *__autoreleasing *)error {
[query setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible];
}
#endif

#if __IPHONE_8_0 || __MAC_10_10
if (self.useNoAuthenticationUI) {
[query setObject:self.useNoAuthenticationUI forKey:(__bridge id)kSecUseNoAuthenticationUI];
}
if (self.accessControl) {
CFErrorRef sacError = NULL;
SecAccessControlRef sacObject;

sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
getSecAttrAccessibility(self.accessControl.accessibility),
(CFIndex)self.accessControl.flags,
&sacError);

if (sacObject == NULL || sacError != NULL) {
if (error) {
*error = (__bridge NSError *)sacError;
}
return NO;
}

[query setObject:(__bridge id)sacObject forKey:(__bridge id)kSecAttrAccessControl];
}
#endif

status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);

if (status != errSecSuccess && error != NULL) {
Expand All @@ -57,6 +82,44 @@ - (BOOL)save:(NSError *__autoreleasing *)error {
return (status == errSecSuccess);
}

- (BOOL)update:(NSError *__autoreleasing *)error
{
OSStatus status = SSKeychainErrorBadArguments;
if (!self.service || !self.account || !self.passwordData) {
if (error) {
*error = [[self class] errorWithCode:status];
}
return NO;
}

NSMutableDictionary *query = [self query];
NSMutableDictionary *changes = [NSMutableDictionary dictionary];

[changes setObject:self.passwordData forKey:(__bridge id)kSecValueData];
if (self.label) {
[changes setObject:self.label forKey:(__bridge id)kSecAttrLabel];
}
#if __IPHONE_4_0 && TARGET_OS_IPHONE
CFTypeRef accessibilityType = [SSKeychain accessibilityType];
if (accessibilityType) {
[changes setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible];
}
#endif

#if __IPHONE_8_0 || __MAC_10_10
if (self.useOperationPrompt) {
[query setObject:self.useOperationPrompt forKey:(__bridge id)kSecUseOperationPrompt];
}
#endif

status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)changes);

if (status != errSecSuccess && error != NULL) {
*error = [[self class] errorWithCode:status];
}

return (status == errSecSuccess);
}

- (BOOL)deleteItem:(NSError *__autoreleasing *)error {
OSStatus status = SSKeychainErrorBadArguments;
Expand Down Expand Up @@ -94,6 +157,12 @@ - (NSArray *)fetchAll:(NSError *__autoreleasing *)error {
[query setObject:@YES forKey:(__bridge id)kSecReturnAttributes];
[query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];

#if __IPHONE_8_0 || __MAC_10_10
if (self.useOperationPrompt) {
[query setObject:self.useOperationPrompt forKey:(__bridge id)kSecUseOperationPrompt];
}
#endif

CFTypeRef result = NULL;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
if (status != errSecSuccess && error != NULL) {
Expand All @@ -118,6 +187,13 @@ - (BOOL)fetch:(NSError *__autoreleasing *)error {
NSMutableDictionary *query = [self query];
[query setObject:@YES forKey:(__bridge id)kSecReturnData];
[query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];

#if __IPHONE_8_0 || __MAC_10_10
if (self.useOperationPrompt) {
[query setObject:self.useOperationPrompt forKey:(__bridge id)kSecUseOperationPrompt];
}
#endif

status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);

if (status != errSecSuccess && error != NULL) {
Expand Down