Hi,
I know I am not explaning the problem correctly, since I am very new to IOS. Better I will add some code snippets to add some clarity.
SSO App:
1. SSO app initially creates X509 certifcate, then convert the same to PKCS12 & adds to Keychain using SecItemAdd
2. Then creates SecIdentityRef object, then import PKCS12 data using SecPKCS12Import
3. Finally adds the SecIdentityRef to the keychain ( SecIdentityRef - is a requirement for internal prupose )
So the problem is SecIdentityRef (certificate) is not removed or deleted as expected.
Code creates SecRefObject & stores to keychain
SecIdentityRef identityApp = nil;
CFDataRef inPKCS12Data = (__bridge CFDataRef)signedDer;
CFStringRef password = CFSTR("");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
CFRelease(options);
CFRelease(password);
if (securityError == errSecSuccess) {
NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
} else {
NSLog(@"Error opening Certificate.");
}
CFDataRef result;
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)identityApp, kSecValueRef,
(id)kCFBooleanTrue, kSecReturnPersistentRef,nil];
OSStatus itemAddStatus = SecItemAdd((__bridge CFDictionaryRef)attributes,(CFTypeRef *)&result);
NSData *dataToStore = (__bridge_transfer NSData *)result;
if (itemAddStatus != errSecSuccess)
{
NSLog(@"SecItemAdd did not succeed %d", (int)itemAddStatus);
}else{
NSLog(@"SecItemAdd was successful");
}
[UICKeyChainStore setData:dataToStore forKey:@"secIdentityRef" service:@"SSOService"];
Code to retirve items for service:
+ (NSArray *)itemsForService:(NSString *)service accessGroup:(NSString *)accessGroup
{
if (!service) {
service = [self defaultService];
}
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[query setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes];
[query setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
[query setObject:service forKey:(__bridge id)kSecAttrService];
#if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
if (accessGroup) {
[query setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
}
#endif
CFArrayRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
if (status == errSecSuccess || status == errSecItemNotFound) {
return CFBridgingRelease(result);
} else {
return nil;
}
}
Function gets invoke when user resets/deletes certificate
(BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup
{
NSArray *items = [UICKeyChainStore itemsForService:service accessGroup:accessGroup];
for (NSDictionary *item in items) {
NSMutableDictionary *itemToDelete = [[NSMutableDictionary alloc] initWithDictionary:item];
[itemToDelete setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[itemToDelete setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)itemToDelete);
if (status != errSecSuccess) {
return NO;
}
}
return YES;
}
Services App:
Services app reads the certificate created by SSO app & displays the same for user to pick before login, to authenticate
Services app supposed to display only one active certificate, but due to the above problem certificate list is keeps growing indefintely
Kindly suggest a work around to fix this, thanks a lot.
Rajesh