I work on an app which have to accessing keychain items with biometric method( face id or touch id) . We have received an issue that is user installed the app and do registration to insert the data into keychain for later use, then delete and reinstall the app . When user try to do the registration againn, keychain SecItemAdd method failed with error code -25330. The user use iPhone 12(iOS 14.3) and it happen irregularly.
The log:
18:35:44.261389+0800 securityd deleted genp,acct=,svce=,agrp=XXXXX,sync=0,musr=, |otherAttr,tomb=0,rowid=78066,cdat=2021-04-29 10:35:44 +0000,mdat=2021-04-29 10:35:44 +0000,sha1=823CD54A2E06C44D941F0C349CBAEC06FBEEC1E2,accc=318183300C0C0470726F740C04616B707530730C0361636C316C30070C026F6501010130090C046F64656C01010130560C026F643150304E0C046362696F314630190C057062696F630410186F86E694AB529847803D3747422E2B30290C057062696F680420467A9C1598FB013ECA1030956B7E73C7CF030994BB45BA21268D111593093233,UUID=F07953A7-55A0-46E0-9052-7B98833B5B03,persistref=,clip=0 from SecDbConnection rw open
18:35:44.263070+0800 securityd insert failed for item genp,acct=bio_account_46323731353237383231,svce=bio_service_46323731353237383231,agrp=XXXXX,sync=0,musr=, |otherAttr,tomb=0,cdat=2021-04-29 10:35:44 +0000,mdat=2021-04-29 10:35:44 +0000,labl=636F6D2E656E74696562616E6B2E6170702E7561742E4175746853444B,pdmn=akpu,sha1=BE484AB751AC112E689819E3D83A2FDD45A73D8E,v_Data=?,accc=3153300C0C0470726F740C04616B707530430C0361636C313C30070C026F6501010130090C046F64656C01010130260C026F643120301E0C046362696F311630090C057062696F63040030090C057062696F680400,UUID=E76CF22A-67CD-4CEC-B522-1C2700C58FB6,persistref=,clip=0 with Error Domain=NSOSStatusErrorDomain Code=-25330 "(null)" UserInfo={-25330=(
(
{length = 85, bytes = 0x3153300c 0c047072 6f740c04 616b7075 ... 03706279 6f680410 },
""
)
)}
The related code:
ViewController
objective-c
(IBAction)registerAction:(id)sender {
NSString *service = [NSString stringWithFormat:@"bio_service_%@", username];
NSString *account = [NSString stringWithFormat:@"bio_account_%@", username];
BOOL success = [Keychain insertBioAuthDataWithAccount:account service:service generic:nil data:data];
if (success) {
// do something
}
// error handling
}
code for insert into keychain
objective-c (NSMutableDictionary*) prepareBioAuthDictWithAccount:(NSString *) account service:(NSString*) service generic:(NSString*) generic bioMsg:(NSString*)bioMsg
{
CFErrorRef *err = nil;
SecAccessControlRef sacRef = nil;
if (@available(iOS 11.3, *)) {
sacRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlBiometryCurrentSet,
err);
} else {
// Fallback on earlier versions
sacRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlTouchIDCurrentSet,
err);
}
if(err){
return nil;
}
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
if([account isKindOfClass:[NSString class]]){
[dict setObject:account forKey:(__bridge id)kSecAttrAccount];
}
if([service isKindOfClass:[NSString class]]){
[dict setObject:service forKey:(__bridge id)kSecAttrService];
}
if([generic isKindOfClass:[NSString class]]){
[dict setObject:generic forKey:(__bridge id)kSecAttrGeneric];
}
[dict setObject:(__bridge_transfer id)sacRef forKey:(__bridge id)kSecAttrAccessControl];
[dict setObject:bioMsg forKey:(__bridge id)kSecUseOperationPrompt];
[dict setObject:[Keychain queryLabel] forKey:(__bridge id)kSecAttrLabel];
[dict setObject:[Keychain accessGroup] forKey:(__bridge id )kSecAttrAccessGroup];
return dict;
}
(BOOL) insertBioAuthDataWithAccount:(NSString*)account service:(NSString*) service generic:(NSString*) generic data:(NSData *)data
{
NSMutableDictionary * dict = nil;
OSStatus status = 0;
dict =[[self class] prepareBioAuthDictWithAccount:account service:service generic:generic bioMsg:@""];
if(!dict){
return false;
}
[dict setObject:data forKey:(__bridge id)kSecValueData];
SecItemDelete((__bridge CFDictionaryRef)dict);
status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
if(errSecSuccess != status) {
NSLog(@"Unable add item with key =%@|%@|%@ error:%d",account, service, generic, (int)status);
}
return (errSecSuccess == status);
Has anyone got any ideas why this is happening and how to fix it ? Thanks.