The following sample uses the kSecAccessControlBiometryAny flag, which is part of the biometric authentication API and can allow unauthorized access. This flag does not ensure that the associated keychain item becomes inaccessible when changes are made to the biometric database (e.g., when a new fingerprint or face is added). Consequently, users who enroll their biometric data after the item is created can unlock it.
importSwiftUIimportLocalAuthenticationimportSecuritystructMastgTest{staticfuncmastgTest(completion:@escaping(String)->Void){letaccount="com.mastg.sectoken"lettokenData="8767086b9f6f976g-a8df76".data(using:.utf8)!//1.StorethetokenintheKeychainwithACLflags//1a.Createanaccess‐controlobjectrequiringuserpresenceguardletaccessControl=SecAccessControlCreateWithFlags(nil,kSecAttrAccessibleWhenUnlocked,.biometryAny,nil)else{completion("❌ Failed to create access control")return}//1b.Buildyouradd‐itemquery//Optional:youmayprovideacustomizedcontexttoalterthedefaultconfig,e.g.toseta"reuse duration".//Seehttps://developer.apple.com/documentation/localauthentication/accessing-keychain-items-with-face-id-or-touch-id#Optionally-Provide-a-Customized-Context//KeychainservicesautomaticallymakesuseoftheLocalAuthenticationframework,evenifyoudon't provide one.////letcontext=LAContext()//context.touchIDAuthenticationAllowableReuseDuration=10letstoreQuery:[String:Any]=[kSecClassasString:kSecClassGenericPassword,kSecAttrAccountasString:account,kSecValueDataasString:tokenData,kSecAttrAccessControlasString:accessControl,//kSecUseAuthenticationContextasString:context,]//Beforeadding,wedeleteanyexistingitemSecItemDelete(storeQueryasCFDictionary)letstoreStatus=SecItemAdd(storeQueryasCFDictionary,nil)guardstoreStatus==errSecSuccesselse{completion("❌ Failed to store token in Keychain (status \(storeStatus))")return}//2.Nowlet's retrieve the token//Optional:youmayprovideacontextwithalocalizedreason.//Seehttps://developer.apple.com/documentation/localauthentication/accessing-keychain-items-with-face-id-or-touch-id#Provide-a-Prompt-When-Reading-the-Item//KeychainserviceswilluseLAContexttoprompttheuserevenifyoudon't provide one.////letcontext=LAContext()//context.localizedReason="Access your token from the keychain"letfetchQuery:[String:Any]=[kSecClassasString:kSecClassGenericPassword,kSecAttrAccountasString:account,kSecReturnDataasString:true,kSecMatchLimitasString:kSecMatchLimitOne,//kSecUseAuthenticationContextasString:context,]varresult:CFTypeRef?letfetchStatus=SecItemCopyMatching(fetchQueryasCFDictionary,&result)iffetchStatus==errSecSuccess,letdata=resultas?Data,lettoken=String(data:data,encoding:.utf8){completion("✅ Retrieved token: \(token)")}else{completion("❌ Authentication failed or token inaccessible (status \(fetchStatus))")}}}
Unzip the app package and locate the main binary file ( Exploring the App Package), which in this case is ./Payload/MASTestApp.app/MASTestApp.
Run run.sh.
biometricAuthenticationEnrollmentChange.r2
1 2 3 4 5 6 7 8 91011121314
easm.bytes=falseescr.color=falseeasm.var=false?ePrintxrefsto \'Run analysis\"aaa?ePrintxrefsto \'SecAccessControlCreateWithFlags\"axt@sym.imp.SecAccessControlCreateWithFlags?e?ePrintdisassemblyaround \"SecAccessControlCreateWithFlags\" in the functionpdf@0x100004194|grep-C5"SecAccessControlCreateWithFlags"
The output reveals the use of SecAccessControlCreateWithFlags(allocator, protection, flags, error) in the app. In this demo, we focus on the flags argument because it specifies the Access Control. flags is the third argument of the function, so it's at x2/w2 register. By looking at the output, we can see that w2 register holds value of 2.
The flags is an enum of SecAccessControlCreateFlags. 2 corresponds to kSecAccessControlBiometryAny (see LAPublicDefines.h). This means that the app invokes SecAccessControlCreateWithFlags(..., kSecAccessControlBiometryAny), which means it will accept new biometric added in the system settings.
The test fails because the output shows a reference to SecAccessControlCreateWithFlags with kSecAccessControlBiometryAny, which accepts any additional biometrics added after the Keychain entry was created.
When it is required that the associated keychain item become inaccessible when changes are made to the biometric database (e.g., when a new fingerprint or face is added), the app must use thekSecAccessControlBiometryCurrentSet flag instead.