Keychain SecItemAdd failed with error code -25330

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

Code Block 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

Code Block 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.

Error -25330 is not in the public SDK (*grumble*) but if you look at the Darwin source you’ll see that it’s defined as errSecAuthNeeded. The comment there says:

An array of constraints to be fulfilled is passed inside
error.userInfo’s 'cons' key.

which suggests that it’d be helpful to get a full dump of the error’s userInfo property. Unfortunately the dump you have:

Code Block
-25330=(
(
{length = 85, bytes = 0x3153300c 0c047072 6f740c04 616b7075 ... 03706279 6f680410 },
""
)
)


has been truncated. Can you send this user a development build that logs this properly?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Keychain SecItemAdd failed with error code -25330
 
 
Q