Enumerate All Keychain Items in My iOS Application

Enumerate all Keychain items in my iOS application

SecItemCopyMatching is the right call for that. First we build our query dictionary so that the items' attributes are returned in dictionaries, and that all items are returned:

NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
(__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
nil];

As SecItemCopyMatching requires at least the class of the returned SecItems, we create an array with all the classes…

NSArray *secItemClasses = [NSArray arrayWithObjects:
(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
(__bridge id)kSecClassCertificate,
(__bridge id)kSecClassKey,
(__bridge id)kSecClassIdentity,
nil];

...and for each class, set the class in our query, call SecItemCopyMatching, and log the result.

for (id secItemClass in secItemClasses) {
[query setObject:secItemClass forKey:(__bridge id)kSecClass];

CFTypeRef result = NULL;
SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
NSLog(@"%@", (__bridge id)result);
if (result != NULL) CFRelease(result);
}

In production code, you should check that the OSStatus returned by SecItemCopyMatching is either errSecItemNotFound (no items found) or errSecSuccess (at least one item was found).

How can I enumerate all Keychain items in my OS X application?

You're providing an empty dictionary and not a valid query.

If you take the code from the answer you were looking at and drop it into your project:

NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
(__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
nil];

NSArray *secItemClasses = [NSArray arrayWithObjects:
(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
(__bridge id)kSecClassCertificate,
(__bridge id)kSecClassKey,
(__bridge id)kSecClassIdentity,
nil];

for (id secItemClass in secItemClasses) {
[query setObject:secItemClass forKey:(__bridge id)kSecClass];

CFTypeRef result = NULL;
SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
NSLog(@"%@", (__bridge id)result);
if (result != NULL) CFRelease(result);
}

You'll have a happier result.

EDITED to add the CoreFoundation equivalent

There's no reason why you can't include the Cocoa framework in your MacOS command line tool (which is what I'm assuming you are writing). What a command line tool can't easily include is the AppKit UI framework.

Anyways, here is the CoreFoundation equivalent:

CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);


CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);

CFTypeRef types[5];

types[0] = kSecClassGenericPassword;
types[1] = kSecClassInternetPassword;
types[2] = kSecClassCertificate;
types[3] = kSecClassKey;
types[4] = kSecClassIdentity;

CFArrayRef secItemClasses = CFArrayCreate(NULL, (void *)types, 5, &kCFTypeArrayCallBacks);
CFIndex i, c = CFArrayGetCount(secItemClasses);

for(i = 0; i{
CFTypeRef secItemClass = CFArrayGetValueAtIndex(secItemClasses,i);
CFDictionarySetValue(query, kSecClass, secItemClass);

CFTypeRef result = NULL;
SecItemCopyMatching(query, &result);
NSLog(@"%@", (__bridge id)result);
if (result != NULL) CFRelease(result);
}

CFRelease(secItemClasses);
CFRelease(query);

When I put this into my own test app, I'm seeing quite a large dump of various keychain items and certificates.

How to delete all keychain items accessible to an app?

Do it for all classes

Objective-C:

NSArray *secItemClasses = @[(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
(__bridge id)kSecClassCertificate,
(__bridge id)kSecClassKey,
(__bridge id)kSecClassIdentity];
for (id secItemClass in secItemClasses) {
NSDictionary *spec = @{(__bridge id)kSecClass: secItemClass};
SecItemDelete((__bridge CFDictionaryRef)spec);
}

Swift:

let secItemClasses = [kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey, kSecClassIdentity]
for itemClass in secItemClasses {
let spec: NSDictionary = [kSecClass: itemClass]
SecItemDelete(spec)
}

Swift 4 Get Keychain Data from Another Project

Not at this point.

You are able to add multiple applications to a Keychain Access Group within an app, but you would have had to do that within the original app you no longer have access to.

More information on Keychain Access Groups.

It would be a big security concern if anyone could access anything within keychain without explicit permission.

Sharing Keychain Items in iOS

You can refer to the Apple documentation here: https://developer.apple.com/library/ios/documentation/security/Reference/keychainservices/Reference/reference.html

It details how to share items across two or more apps using a keychain-access-groups entitlement

Private Keychain store

You can't.

The security boundary for the KeyChain is the app (Or the KeyChain identifier across multiple apps from the same developer if you enable KeyChain sharing).

Once your framework is embedded in the client app, it is part of the client app. It doesn't have its own context or process space or anything to distinguish its code from the client code.

If code in your framework puts something in the KeyChain then, to iOS, it is the client app that has put something in the KeyChain, and there is no reason to keep a secret from itself.

Even if you could create a KeyChain just for your framework, presumably the code that puts the information in the KeyChain is in your framework, so an attacker could just decompile your framework to obtain the information.

Can we access keychain items that are saved before enabling keychain sharing from app sharing same app group?

Before enabling keychain sharing all keychain items "accessGroup" is (AppIdentifierPrefix).bundleIdentifier, which is changed to (AppIdentifierPrefix).keyChainGroupName after turning it on.

Workaround is to remove all keychain items by accessing those through keychains.

AWSUICKeyChainStore *keychain = [AWSUICKeyChainStore keyChainStoreWithService:@"ServiceName"];
for (NSDictionary *dictionary in keychain.allItems)
if ([dictionary[@"accessGroup"] isEqualToString:"(AppIdentifierPrefix).bundleIdentifier"])
[keychain removeItemForKey:dictionary[@"key"]];

How to detect if iOS Keychain items not available yet? (before first unlock)

As far as I know "Error Code -25308 (errSecInteractionNotAllowed)" is returned, but I haven't been able to verify yet.

Source: https://developer.apple.com/documentation/security/1542001-security_framework_result_codes/errsecinteractionnotallowed?language=objc

How to list certificates from the iPhone keychain inside my app?

The Junos Pulse app is apparently getting its access via a VPN plugin which is a private API supplied by Apple on an invitation-only basis. That API is giving the app access to those certificates otherwise accessible only to built-in iOS apps like Safari.

Review the following which were very helpful when I was researching the topic:
iOS get Configuration Profiles that are installed
(Apple Development post linked in one of the answers)
https://devforums.apple.com/message/660579#660579



Related Topics



Leave a reply



Submit