From 8188056386b5bba1e8e7f877086645b61649e14c Mon Sep 17 00:00:00 2001 From: Alexsander Akers Date: Wed, 22 Oct 2014 00:24:44 +0100 Subject: [PATCH 1/5] Assign values to result dictionary keys at runtime --- SSKeychain/SSKeychain.h | 14 +++++++------- SSKeychain/SSKeychain.m | 25 ++++++++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/SSKeychain/SSKeychain.h b/SSKeychain/SSKeychain.h index 94fa0d0..d80949c 100644 --- a/SSKeychain/SSKeychain.h +++ b/SSKeychain/SSKeychain.h @@ -22,32 +22,32 @@ typedef NS_ENUM(OSStatus, SSKeychainErrorCode) { extern NSString *const kSSKeychainErrorDomain; /** Account name. */ -extern NSString *const kSSKeychainAccountKey; +extern NSString *kSSKeychainAccountKey; /** Time the item was created. The value will be a string. */ -extern NSString *const kSSKeychainCreatedAtKey; +extern NSString *kSSKeychainCreationDateKey; /** Item class. */ -extern NSString *const kSSKeychainClassKey; +extern NSString *kSSKeychainClassKey; /** Item description. */ -extern NSString *const kSSKeychainDescriptionKey; +extern NSString *kSSKeychainDescriptionKey; /** Item label. */ -extern NSString *const kSSKeychainLabelKey; +extern NSString *kSSKeychainLabelKey; /** Time the item was last modified. The value will be a string. */ -extern NSString *const kSSKeychainLastModifiedKey; +extern NSString *kSSKeychainModificationDateKey; /** Where the item was created. */ -extern NSString *const kSSKeychainWhereKey; +extern NSString *kSSKeychainServiceKey; /** Simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system diff --git a/SSKeychain/SSKeychain.m b/SSKeychain/SSKeychain.m index 36337ba..e8c341c 100644 --- a/SSKeychain/SSKeychain.m +++ b/SSKeychain/SSKeychain.m @@ -9,13 +9,13 @@ #import "SSKeychain.h" NSString *const kSSKeychainErrorDomain = @"com.samsoffes.sskeychain"; -NSString *const kSSKeychainAccountKey = @"acct"; -NSString *const kSSKeychainCreatedAtKey = @"cdat"; -NSString *const kSSKeychainClassKey = @"labl"; -NSString *const kSSKeychainDescriptionKey = @"desc"; -NSString *const kSSKeychainLabelKey = @"labl"; -NSString *const kSSKeychainLastModifiedKey = @"mdat"; -NSString *const kSSKeychainWhereKey = @"svce"; +NSString *kSSKeychainAccountKey; +NSString *kSSKeychainCreationDateKey; +NSString *kSSKeychainClassKey; +NSString *kSSKeychainDescriptionKey; +NSString *kSSKeychainLabelKey; +NSString *kSSKeychainModificationDateKey; +NSString *kSSKeychainServiceKey; #if __IPHONE_4_0 && TARGET_OS_IPHONE static CFTypeRef SSKeychainAccessibilityType = NULL; @@ -23,6 +23,17 @@ @implementation SSKeychain ++ (void)load { + kSSKeychainAccountKey = (__bridge id)kSecAttrAccount; + kSSKeychainCreationDateKey = (__bridge id)kSecAttrCreationDate; + kSSKeychainClassKey = (__bridge id)kSecClass; + kSSKeychainDescriptionKey = (__bridge id)kSecAttrDescription; + kSSKeychainLabelKey = (__bridge id)kSecAttrLabel; + kSSKeychainModificationDateKey = (__bridge id)kSecAttrModificationDate; + kSSKeychainServiceKey = (__bridge id)kSecAttrService; +} + + + (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account { return [self passwordForService:serviceName account:account error:nil]; } From 2aa94009206f8f1247eb3063b23abb7d462d48c4 Mon Sep 17 00:00:00 2001 From: Alexsander Akers Date: Wed, 22 Oct 2014 00:26:52 +0100 Subject: [PATCH 2/5] Remove Mac-only code in -[SSKeychainQuery delete:] SecItemDelete is available starting on OS X 10.6; surely that's fine. --- SSKeychain/SSKeychainQuery.m | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/SSKeychain/SSKeychainQuery.m b/SSKeychain/SSKeychainQuery.m index b93c620..78135e3 100644 --- a/SSKeychain/SSKeychainQuery.m +++ b/SSKeychain/SSKeychainQuery.m @@ -68,17 +68,7 @@ - (BOOL)deleteItem:(NSError *__autoreleasing *)error { } NSMutableDictionary *query = [self query]; -#if TARGET_OS_IPHONE status = SecItemDelete((__bridge CFDictionaryRef)query); -#else - CFTypeRef result = NULL; - [query setObject:@YES forKey:(__bridge id)kSecReturnRef]; - status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); - if (status == errSecSuccess) { - status = SecKeychainItemDelete((SecKeychainItemRef)result); - CFRelease(result); - } -#endif if (status != errSecSuccess && error != NULL) { *error = [[self class] errorWithCode:status]; From 24f061d9cca3c4124840c82c44ac1a9295647355 Mon Sep 17 00:00:00 2001 From: Alexsander Akers Date: Wed, 22 Oct 2014 00:27:47 +0100 Subject: [PATCH 3/5] Update existing keychain item before creating one Previously, the existing keychain item was always deleted and then re-created. --- SSKeychain/SSKeychainQuery.m | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/SSKeychain/SSKeychainQuery.m b/SSKeychain/SSKeychainQuery.m index 78135e3..1ad9cd3 100644 --- a/SSKeychain/SSKeychainQuery.m +++ b/SSKeychain/SSKeychainQuery.m @@ -35,20 +35,30 @@ - (BOOL)save:(NSError *__autoreleasing *)error { return NO; } - [self deleteItem:nil]; - NSMutableDictionary *query = [self query]; - [query setObject:self.passwordData forKey:(__bridge id)kSecValueData]; + [query setObject:@YES forKey:(__bridge id)kSecReturnData]; + [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; + + NSMutableDictionary *updates = [NSMutableDictionary dictionaryWithCapacity:2]; + [updates setObject:self.passwordData forKey:(__bridge id)kSecValueData]; if (self.label) { - [query setObject:self.label forKey:(__bridge id)kSecAttrLabel]; + [updates setObject:self.label forKey:(__bridge id)kSecAttrLabel]; } + #if __IPHONE_4_0 && TARGET_OS_IPHONE CFTypeRef accessibilityType = [SSKeychain accessibilityType]; if (accessibilityType) { - [query setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible]; + [updates setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible]; } #endif - status = SecItemAdd((__bridge CFDictionaryRef)query, NULL); + + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL); + if (status == errSecSuccess) { + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)updates); + } else if (status == errSecItemNotFound) { + [query addEntriesFromDictionary:updates]; + status = SecItemAdd((__bridge CFDictionaryRef)query, NULL); + } if (status != errSecSuccess && error != NULL) { *error = [[self class] errorWithCode:status]; From 24910ec0437337701405d920fe079088b6627251 Mon Sep 17 00:00:00 2001 From: Alexsander Akers Date: Wed, 22 Oct 2014 00:45:15 +0100 Subject: [PATCH 4/5] Remove extraneous parentheses --- SSKeychain/SSKeychainQuery.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SSKeychain/SSKeychainQuery.m b/SSKeychain/SSKeychainQuery.m index 1ad9cd3..b311869 100644 --- a/SSKeychain/SSKeychainQuery.m +++ b/SSKeychain/SSKeychainQuery.m @@ -207,12 +207,12 @@ - (NSMutableDictionary *)query { break; } case SSKeychainQuerySynchronizationModeAny: { - value = (__bridge id)(kSecAttrSynchronizableAny); + value = (__bridge id)kSecAttrSynchronizableAny; break; } } - [dictionary setObject:value forKey:(__bridge id)(kSecAttrSynchronizable)]; + [dictionary setObject:value forKey:(__bridge id)kSecAttrSynchronizable]; } #endif From cf339f3e2fceffa8093694919dc4c11a597d2c96 Mon Sep 17 00:00:00 2001 From: Alexsander Akers Date: Wed, 22 Oct 2014 00:46:46 +0100 Subject: [PATCH 5/5] Revert "Remove Mac-only code in -[SSKeychainQuery delete:]" This reverts commit 2aa94009206f8f1247eb3063b23abb7d462d48c4. --- SSKeychain/SSKeychainQuery.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/SSKeychain/SSKeychainQuery.m b/SSKeychain/SSKeychainQuery.m index b311869..8b68417 100644 --- a/SSKeychain/SSKeychainQuery.m +++ b/SSKeychain/SSKeychainQuery.m @@ -78,7 +78,17 @@ - (BOOL)deleteItem:(NSError *__autoreleasing *)error { } NSMutableDictionary *query = [self query]; +#if TARGET_OS_IPHONE status = SecItemDelete((__bridge CFDictionaryRef)query); +#else + CFTypeRef result = NULL; + [query setObject:@YES forKey:(__bridge id)kSecReturnRef]; + status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); + if (status == errSecSuccess) { + status = SecKeychainItemDelete((SecKeychainItemRef)result); + CFRelease(result); + } +#endif if (status != errSecSuccess && error != NULL) { *error = [[self class] errorWithCode:status];