Hi everyone,
I'm working on an app that stores multiple secrets in the Keychain, each protected with .userPresence.
My goal is to authenticate the user once via FaceID/TouchID and then read multiple Keychain items without triggering subsequent prompts.
I am reusing the same LAContext instance for these operations, and I have set:
context.touchIDAuthenticationAllowableReuseDuration = LATouchIDAuthenticationMaximumAllowableReuseDuration
However, I'm observing that every single SecItemCopyMatching call triggers a new FaceID/TouchID prompt, even if they happen within seconds of each other using the exact same context.
Here is a simplified flow of what I'm doing:
Create a LAContext.
Set touchIDAuthenticationAllowableReuseDuration to max.
Perform a query (SecItemCopyMatching) for Item A, passing [kSecUseAuthenticationContext: context].
Result: System prompts for FaceID. Success.
Immediately perform a query (SecItemCopyMatching) for Item B, passing the same [kSecUseAuthenticationContext: context].
Result: System prompts for FaceID again.
My question is:
Does the .userPresence access control flag inherently force a new user interaction for every Keychain access, regardless of the LAContext reuse duration? Is allowableReuseDuration only applicable for LAContext.evaluatePolicy calls and not for SecItem queries?
If so, is there a recommended pattern for "unlocking" a group of Keychain items with a single biometric prompt?
Environment: iOS 17+, Swift.
Thanks!
Prioritize user privacy and data security in your app. Discuss best practices for data handling, user consent, and security measures to protect user information.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Hello,
I have a question regarding the lifecycle of user consent and tokens in "Sign in with Apple." Specifically, I would like to understand the behavior of the auth/revoke API in relation to App Store Connect status changes.
Impact of App Status Changes If an app is "Removed from Sale" or "Deleted" from App Store Connect, does Apple automatically revoke all associated user tokens and consent? Or is it still the developer's responsibility to programmatically revoke each user's token via the REST API to ensure the app is removed from the user’s "Apps Using Apple ID" list?
API Availability after Removal Once an app is no longer available on the App Store (or its record is deleted in App Store Connect), is the auth/revoke REST API still accessible? I want to ensure that a developer can still perform necessary privacy clean-up tasks (revoking consent) even if the app is not currently distributed.
Specific User Impacts of Non-Revocation If we do not call the revocation API, besides the app remaining in the "Sign in with Apple" list, what are the specific consequences for the user?
Thank you for your guidance.
On iOS 26, QuickLookAR (ARQuickLookPreviewItem) shares the actual .usdz file via the system Share Sheet instead of the original website URL.
This is a regression from iOS 17–18, where sharing correctly preserved and sent only the source URL.
Repro steps:
1. Open a web-hosted USDZ model in QuickLookAR (Safari).
2. Tap Share.
3. Share via any messenger.
4. The full .usdz file is sent.
Expected:
Share Sheet sends only the original URL.
Actual:
Share Sheet sends the USDZ file.
Impact:
Uncontrolled distribution of proprietary 3D assets.
Critical IP / data leak.
Blocks production AR deployments relying on QuickLook.
Environment:
iOS 26.0–26.1, iPhone 14 / 15.
Works as expected on iOS 17–18.
Test case:
https://admixreality.com/ios26/
Topic:
Privacy & Security
SubTopic:
General
QuickLookAR shares the actual USDZ model instead of the original website URL — critical copyright and data leak issue on iOS 26
Since iOS 26, QuickLookAR (or ARQuickLookPreviewItem) no longer preserves the original web URL when sharing a model.
Instead of sending the link to the hosted file, the system directly shares the actual USDZ model file with the recipient.
This is a critical regression and a severe breach of intellectual property protection, as it exposes proprietary 3D models that must never be distributed outside of the controlled web environment.
In earlier iOS versions (tested up to iOS 18), QuickLookAR correctly handled sharing — the share sheet would send the website link where the model is hosted, not the file itself.
Starting with iOS 26, this behavior has changed and completely breaks the intended secure flow for AR experiences.
Our project relies on allowing users to view models in AR via QuickLook, without ever transferring the underlying 3D assets.
Now, the share operation forces full file sharing, giving end users unrestricted access to the model file, which can be copied, rehosted, or reverse-engineered.
This issue critically affects production environments and prevents us from deploying our AR-based solutions.
Implement a standard QuickLookAR preview with a USDZ file hosted on your web server (e.g., via ARQuickLookPreviewItem).
2. Open the AR view on iOS 26.
3. Tap the Share icon from QuickLookAR.
4. Send via any messenger (Telegram, WhatsApp, etc.).
5. Observe that the actual .usdz model is sent instead of the original website URL.
⸻
Expected behavior:
QuickLookAR should share only the original URL (as in iOS 17–18), not the file itself.
This ensures that intellectual property and licensed 3D models remain protected and controlled by the content owner.
⸻
Actual behavior:
QuickLookAR shares the entire USDZ file, leaking the model content outside of the intended environment.
⸻
Impact:
• Violation of copyright and confidential data policies
• Loss of control over proprietary 3D assets
• Breaking change for all existing web-based AR integrations
• Critical blocker for AR production deployment
⸻
Environment:
• iOS 26.0 and 26.1 (tested on iPhone 14, iPhone 15)
• Safari + QuickLookAR integration
• Works correctly on iOS 17 / iOS 18
⸻
Notes:
This regression appears to have been introduced in the latest iOS 26 system handling of QuickLookAR sharing.
Please escalate this issue to the ARKit / QuickLook engineering team as it directly affects compliance, IP protection, and usability of AR features across production applications.
Additional Notes / Verification:
Please test this behavior yourself using the CheckAR test model on my website: https://admixreality.com/ios26/
• If the login page appears, click “Check AR” and then “View in Your Space”.
• On iOS 18 and earlier, sharing correctly sends the website URL.
• On iOS 26, sharing sends the actual USDZ model file.
This clearly demonstrates the regression and the security/IP issue.
Hello,
we are using DeviceCheck – App Attest in a production iOS app. The integration has been live for some time and works correctly for most users, but a small subset of users encounter non-deterministic failures that we are unable to reproduce internally.
Environment
iOS 14+
Real devices only (no simulator)
App Attest capability enabled
Correct App ID, Team ID and App Attest entitlement
Production environment
Relevant code
let service = DCAppAttestService.shared
service.generateKey { keyId, error in
// key generation
}
service.attestKey(keyId, clientDataHash: hash) { attestation, error in
// ERROR: com.apple.devicecheck.error 3 / 4
}
service.generateAssertion(keyId, clientDataHash: clientDataHash) { assertion, error in
// ERROR: com.apple.devicecheck.error 3 / 4
}
For some users we intermittently receive:
com.apple.devicecheck.error error 3
com.apple.devicecheck.error error 4
Characteristics:
appears random
affects only some users/devices
sometimes resolves after time or reinstall
not reproducible on our test devices
NSError contains no additional diagnostic info
Some questions:
What is the official meaning of App Attest errors 3 and 4?
Are these errors related to key state, device conditions, throttling, or transient App Attest service issues?
Is there any recommended way to debug or gain more insight when this happens in production?
Any guidance would be greatly appreciated, as this impacts real users and is difficult to diagnose.
Thank you.
Hello,
We are experiencing an issue related to Sign in with Apple Server-to-Server (S2S) notifications, specifically involving repeated delivery of the account-deleted event, and would like to ask whether this behavior is expected or known.
Background
We have configured an S2S notification endpoint for Sign in with Apple in accordance with Apple’s requirements for account status change notifications.
Our endpoint:
Is reachable over HTTPS
Consistently returns HTTP 200 OK
Successfully receives other S2S events, including:
email-enabled
email-disabled
consent-revoked
Issue: Repeated 'account-deleted' events for the same Apple ID
For most users, the account-deleted event is delivered only once, as expected.
However, for a specific Apple ID used with Sign in with Apple, we are observing repeated deliveries of the same account-deleted event, arriving at regular intervals (approximately every 5 minutes).
The payload contents are identical between deliveries and include the same user identifier (sub) and event timestamp.
Notably:
The Apple ID deletion itself completed successfully
The payload does not change between deliveries
Our endpoint continues to return HTTP 200 OK for every request
Questions
We would appreciate clarification on the following points:
Is repeated delivery of the same account-deleted event expected behavior in any scenario?
Is there a retry or redelivery mechanism for this event type, even when HTTP 200 is returned?
Could repeated deliveries indicate that the deletion process is still considered “in progress” on Apple’s side?
Are developers expected to treat account-deleted events as at-least-once delivery and handle them idempotently?
Additional context
While researching this issue, we found a forum thread describing a very similar case:
https://developer.apple.com/forums/thread/735674
In that discussion, Apple staff advised submitting the issue via Feedback Assistant, which suggests that this behavior may already be understood internally.
We have also submitted a Feedback Assistant report with detailed logs and timestamps.
Any clarification on the expected behavior or recommended handling for this scenario would be greatly appreciated.
Thank you for your time and support.
I received a notification stating that we need to register a server-to-server notification endpoint to handle the following three events:
Changes in email forwarding preferences.
Account deletions in your app.
Permanent Apple Account deletions.
However, even though we have registered the API endpoint under our Identifier configuration, it appears that we are not receiving any API calls when these events trigger.
I honestly have no idea what’s going wrong. I’ve checked our WAF logs and there’s no trace of any incoming traffic at all. Is it possible that Apple hasn't started sending
these notifications yet, or is there something I might be missing? I’m stuck and don’t know how to resolve this. I would really appreciate any help or insights you could share.
Thank you.
Topic:
Privacy & Security
SubTopic:
Sign in with Apple
I can't find any information about why this is happening, nor can I reproduce the 'successful' state on this device. My team needs to understand this behavior, so any insight would be greatly appreciated!
The expected behavior: If I delete both apps and reinstall them, attempting to open the second app from my app should trigger the system confirmation dialog.
The specifics: I'm using the MSAL library. It navigates the user to the Microsoft Authenticator app and then returns to my app. However, even after resetting the phone and reinstalling both apps, the dialog never shows up (it just opens the app directly).
Does anyone know the logic behind how iOS handles these prompts or why it might be persistent even after a reset?
Thanks in advance!
Topic:
Privacy & Security
SubTopic:
General
I received a notification stating that we need to register a server-to-server notification endpoint to handle the following three events:
Changes in email forwarding preferences.
Account deletions in your app.
Permanent Apple Account deletions.
However, even though we have registered the API endpoint under our Identifier configuration, it appears that we are not receiving any API calls when these events trigger.
I honestly have no idea what’s going wrong. I’ve checked our WAF logs and there’s no trace of any incoming traffic at all. Is it possible that Apple hasn't started sending
these notifications yet, or is there something I might be missing? I’m stuck and don’t know how to resolve this. I would really appreciate any help or insights you could share.
Thank you.
Topic:
Privacy & Security
SubTopic:
Sign in with Apple
I'm implementing Apple Sign-In in my Next.js application with a NestJS backend. After the user authenticates with Apple, instead of redirecting to my configured callback URL, the browser makes a POST request to a mysterious endpoint /appleauth/auth/federate that doesn't exist in my codebase, resulting in a 404 error.
Tech Stack
Frontend: Next.js 16.0.10, React 19.2.0
Backend: NestJS with Passport (using @arendajaelu/nestjs-passport-apple)
Frontend URL: https://myapp.example.com
Backend URL: https://api.example.com
Apple Developer Configuration
Service ID: (configured correctly in Apple Developer Console)
Return URL (only one configured):
https://api.example.com/api/v1/auth/apple/callback
Domains verified in Apple Developer Console:
myapp.example.com
api.example.com
example.com
Backend Configuration
NestJS Controller (auth.controller.ts):
typescript
@Public()
@Get('apple')
@UseGuards(AuthGuard('apple'))
async appleAuth() {
// Initiates Apple OAuth flow
}
@Public()
@Post('apple/callback') // Changed from @Get to @Post for form_post
@UseGuards(AuthGuard('apple'))
async appleAuthCallback(@Req() req: any, @Res() res: any) {
const result = await this.authService.socialLogin(req.user, ipAddress, userAgent);
// Returns HTML with tokens that uses postMessage to send to opener window
}
Environment Variables:
typescript
APPLE_CLIENT_ID=<service_id>
APPLE_TEAM_ID=<team_id>
APPLE_KEY_ID=<key_id>
APPLE_PRIVATE_KEY_PATH=./certs/AuthKey_XXX.p8
APPLE_CALLBACK_URL=https://api.example.com/api/v1/auth/apple/callback
FRONTEND_URL=https://myapp.example.com
The passport-apple strategy uses response_mode: 'form_post', so Apple POSTs the authorization response to the callback URL.
Frontend Implementation
Next.js API Route (/src/app/api/auth/apple/route.js):
javascript
export async function GET(request) {
const backendUrl = new URL(`${API_URL}/auth/apple`);
const response = await fetch(backendUrl.toString(), {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const responseText = await response.text();
return new NextResponse(responseText, {
status: response.status,
headers: { "Content-Type": contentType || "text/html" },
});
}
Frontend Auth Handler:
javascript
export const handleAppleLogin = (router, setApiError) => {
const frontendUrl = window?.location?.origin;
// Opens popup to /api/auth/apple
window.open(
`${frontendUrl}/api/auth/apple`,
"appleLogin",
"width=500,height=600"
);
};
The Problem
Expected Flow:
User clicks "Login with Apple"
Frontend opens popup → https://myapp.example.com/api/auth/apple
Frontend proxies to → https://api.example.com/api/v1/auth/apple
Backend redirects to Apple's authentication page
User authenticates with Apple ID
Apple POSTs back to → https://api.example.com/api/v1/auth/apple/callback
Backend processes and returns success HTML
Actual Behavior:
After step 5 (user authentication with Apple), instead of Apple redirecting to my callback URL, the browser makes this unexpected request:
POST https://myapp.example.com/appleauth/auth/federate?isRememberMeEnabled=false
Status: 404 Not Found
Request Payload:
json
{
"accountName": "user@example.com",
"rememberMe": false
}
Network Tab Analysis
From Chrome DevTools, the call stack shows:
send @ app.js:234
ajax @ app.js:234
(anonymous) @ app.js:10
Ee.isFederated @ app.js:666
_callAuthFederate @ app.js:666
The Ee.isFederated and _callAuthFederate functions appear to be minified library code, but I cannot identify which library.
What I've Verified
✅ The /appleauth/auth/federate endpoint does not exist anywhere in my codebase:
bash
grep -r "appleauth" src/ # No results
grep -r "federate" src/ # No results
✅ Apple Developer Console shows only ONE Return URL configured (verified multiple times)
✅ Changed callback route from @Get to @Post to handle form_post response mode
✅ Rebuilt frontend completely multiple times:
bash
rm -rf .next
npm run build
✅ Tested in:
Incognito/Private browsing mode
Different browsers (Chrome, Firefox, Safari)
Different devices
After clearing all cache and cookies
✅ No service workers registered in the application
✅ No external <script> tags or CDN libraries loaded
✅ package.json contains no AWS Amplify, Auth0, Cognito, or similar federated auth libraries
✅ Checked layout.js and all root-level files - no external scripts
Additional Context
Google Sign-In works perfectly fine using the same approach
The mysterious endpoint uses a different path structure (/appleauth/ vs /api/auth/)
The call appears to originate from client-side JavaScript (based on the call stack)
The app.js file with the mysterious functions is the built Next.js bundle
Questions
Where could this /appleauth/auth/federate endpoint be coming from?
Why is the browser making this POST request instead of following Apple's redirect to my configured callback URL?
Could this be related to the response_mode: 'form_post' in the Apple Passport strategy?
Is there something in the Apple Developer Primary App ID configuration that could trigger this behavior?
Could this be a Next.js build artifact or some hidden dependency?
The mysterious call stack references (Ee.isFederated, _callAuthFederate) suggest some library is intercepting the Apple authentication flow, but I cannot identify what library or where it's being loaded from. The minified function names suggest federated authentication, but I have no such libraries in my dependencies.
Has anyone encountered similar issues with Apple Sign-In where an unexpected endpoint is being called?
Topic:
Privacy & Security
SubTopic:
Sign in with Apple
Tags:
Sign in with Apple REST API
Sign in with Apple
(Xcode 26.2, iPhone 17 Pro)
I can't seem to get hardware tag checks to work in an app launched without the special "Hardware Memory Tagging" diagnostics. In other words, I have been unable to reproduce the crash example at 6:40 in Apple's video "Secure your app with Memory Integrity Enforcement".
When I write a heap overflow or a UAF, it is picked up perfectly provided I enable the "Hardware Memory Tagging" feature under Scheme Diagnostics.
If I instead add the Enhanced Security capability with the memory-tagging related entitlements:
I'm seeing distinct memory tags being assigned in pointers returned by malloc (without the capability, this is not the case)
Tag mismatches are not being caught or enforced, regardless of soft mode
The behaviour is the same whether I launch from Xcode without "Hardware Memory Tagging", or if I launch the app by tapping it on launchpad. In case it was related to debug builds, I also tried creating an ad hoc IPA and it didn't make any difference.
I realise there's a wrinkle here that the debugger sets MallocTagAll=1, so possibly it will pick up a wider range of issues. However I would have expected that a straight UAF would be caught. For example, this test code demonstrates that tagging is active but it doesn't crash:
#define PTR_TAG(p) ((unsigned)(((uintptr_t)(p) >> 56) & 0xF))
void *p1 = malloc(32);
void *p2 = malloc(32);
void *p3 = malloc(32);
os_log(OS_LOG_DEFAULT, "p1 = %p (tag: %u)\n", p1, PTR_TAG(p1));
os_log(OS_LOG_DEFAULT, "p2 = %p (tag: %u)\n", p2, PTR_TAG(p2));
os_log(OS_LOG_DEFAULT, "p3 = %p (tag: %u)\n", p3, PTR_TAG(p3));
free(p2);
void *p2_realloc = malloc(32);
os_log(OS_LOG_DEFAULT, "p2 after free+malloc = %p (tag: %u)\n", p2_realloc, PTR_TAG(p2_realloc));
// Is p2_realloc the same address as p2 but different tag?
os_log(OS_LOG_DEFAULT, "Same address? %s\n",
((uintptr_t)p2 & 0x00FFFFFFFFFFFFFF) == ((uintptr_t)p2_realloc & 0x00FFFFFFFFFFFFFF)
? "YES" : "NO");
// Now try to use the OLD pointer p2
os_log(OS_LOG_DEFAULT, "Attempting use-after-free via old pointer p2...\n");
volatile char c = *(volatile char *)p2; // Should this crash?
os_log(OS_LOG_DEFAULT, "Read succeeded! Value: %d\n", c);
Example output:
p1 = 0xf00000b71019660 (tag: 15)
p2 = 0x200000b711958c0 (tag: 2)
p3 = 0x300000b711958e0 (tag: 3)
p2 after free+malloc = 0x700000b71019680 (tag: 7)
Same address? NO
Attempting use-after-free via old pointer p2...
Read succeeded! Value: -55
For reference, these are my entitlements.
[Dict]
[Key] application-identifier
[Value]
[String] …
[Key] com.apple.developer.team-identifier
[Value]
[String] …
[Key] com.apple.security.hardened-process
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.checked-allocations
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.checked-allocations.enable-pure-data
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.dyld-ro
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.enhanced-security-version
[Value]
[Int] 1
[Key] com.apple.security.hardened-process.hardened-heap
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.platform-restrictions
[Value]
[Int] 2
[Key] get-task-allow
[Value]
[Bool] true
What do I need to do to make Memory Integrity Enforcement do something outside the debugger?
I've made my first app and encountered an unexpected (potentially existential) issue.
The Manager app is designed to tag 3rd party "plugins" used by a DAW, storing metadata in a local SQLite database, and move them between Active and Inactive folders. This allows management of the plugin collection - the DAW only uses what's in the Active folder.
Permissions are obtained via security-scoped bookmarks on first launch. The app functions as intended: plugin bundles move correctly and the database tracks everything. No information is written to the plugins themselves.
The Problem:
When moving plugins using fs.rename() , the MAS sandbox automatically adds the com.apple.quarantine extended attribute to moved files. When the DAW subsequently rebuilds its plugin cache, it interprets quarantined plugins as "corrupt" or potentially malicious and refuses to load them.
Technical Details:
Moving files with NSFileManager or Node.js fs APIs within sandbox triggers quarantine
Sandboxed apps cannot call xattr -d com.apple.quarantine or use removexattr()
The entitlement com.apple.security.files.user-selected.read-write doesn't grant xattr removal rights
User workaround: run xattr -cr /path/to/plugins in Terminal - not acceptable for professional users
Question:
Is there any MAS-compliant way to move files without triggering quarantine, or to remove the quarantine attribute within the sandbox? The hardened-runtime DMG build works perfectly (no sandbox = no quarantine added).
Any insight appreciated!
冷启动后我们读文件,发现:"error_msg":"未能打开文件“FinishTasks.plist”,因为你没有查看它的权限。
是否有这些问题:
「iOS 26 iPhone 16,2 cold launch file access failure」)
核心内容:多名开发者反馈 iPhone 15 Pro(iOS 26.0/26.1)冷启动时读取 Documents 目录下的 plist 文件提示权限拒绝,切后台再切前台恢复,苹果员工回复「建议延迟文件操作至 applicationDidBecomeActive 后」。
Topic:
Privacy & Security
SubTopic:
General
Is there any way for an iOS app to get a log of all Airdrop transfers originating in all apps on the iOS device e.g. from the last week?
Topic:
Privacy & Security
SubTopic:
General
Hi,
I have an application that uses SecureEnclave keys to protect secrets. By passing an LAContext object to the Secure Enclave operations, authentication state can be preserved across decrypt operations, and you do not need to re-authenticate for doing different operations.
However, for security reasons, I would like to avoid that it is possible to do operations in batch with certain keys generated by the Secure Enclave, by any application. This would avoid malicious binaries to batch-extract all the secrets that are protected by a key from my Secure Enclave, and force to re-authenticate on every operation.
Is there a way to prevent batch operations without re-authenticating for Secure Enclave keys?
thanks,
Remko
Hi Apple Developers,
I'm having a problem with evaluatedPolicyDomainState: on the same device, its value keeps changing and then switching back to the original. My current iOS version is 26.1.
I upgraded my iOS from version 18.6.2 to 26.1.
What could be the potential reasons for this issue?
{
NSError *error;
BOOL success = YES;
char *eds = nil;
int edslen = 0;
LAContext *context = [[LAContext alloc] init];
// test if we can evaluate the policy, this test will tell us if Touch ID is available and enrolled
// success = [context canEvaluatePolicy: LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
if (SystemVersion > 9.3) {
// test if we can evaluate the policy, this test will tell us if Touch ID is available and enrolled
success = [context canEvaluatePolicy: LAPolicyDeviceOwnerAuthentication error:&error];
}
else{
// test if we can evaluate the policy, this test will tell us if Touch ID is available and enrolled
success = [context canEvaluatePolicy: LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
}
if (success)
{
if (@available(iOS 18.0, *)) {
NSData *stateHash = nil;
if ([context respondsToSelector:@selector(domainState)]) {
stateHash = [[context performSelector:@selector(domainState)] performSelector:@selector(stateHash)];
}else{
stateHash = [context evaluatedPolicyDomainState];
}
eds = (char *)stateHash.bytes;
edslen = (int)stateHash.length;
} else {
eds = (char *)[[context evaluatedPolicyDomainState] bytes];
edslen = (int)[[context evaluatedPolicyDomainState] length];
}
CC_SHA256(eds, edslen, uviOut);
*poutlen = CC_SHA256_DIGEST_LENGTH;
}
else
{
*poutlen = 32;
gm_memset(uviOut, 0x01, 32);
}
}
Hello,
I’m working on an authorization plugin which allows users to login and unlock their computer with various methods like a FIDO key. I need to add smart cards support to it. If I understand correctly, I need to construct a URLCredential object with the identity from the smart card and pass it to the completion handler of URLSessionDelegate.urlSession(_:didReceive:completionHandler:) method. I’ve read the documentation at Using Cryptographic Assets Stored on a Smart Card, TN3137: On Mac keychain APIs and implementations, and SecItem: Pitfalls and Best Practices and created a simple code that reads the identities from the keychain:
CFArrayRef identities = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)@{
(id)kSecClass: (id)kSecClassIdentity,
(id)kSecMatchLimit: (id)kSecMatchLimitAll,
(id)kSecReturnRef: @YES,
}, (CFTypeRef *)&identities);
if (status == errSecSuccess && identities) {
os_log(OS_LOG_DEFAULT, "Found identities: %{public}ld\n", CFArrayGetCount(identities));
} else {
os_log(OS_LOG_DEFAULT, "Error: %{public}ld\n", (long)status);
}
When I use this code in a simple demo app, it finds my Yubikey identities without problem. When I use it in my authorization plugin, it doesn’t find anything in system.login.console right and finds Yubikey in authenticate right only if I register my plugin as non-,privileged. I tried modifying the query in various ways, in particular by using SecKeychainCopyDomainSearchList with the domain kSecPreferencesDomainDynamic and adding it to the query as kSecMatchSearchList and trying other SecKeychain* methods, but ended up with nothing. I concluded that the identities from a smart card are being added to the data protection keychain rather than to a file based keychain and since I’m working in a privileged context, I won’t be able to get them. If this is indeed the case, could you please advise how to proceed? Thanks in advance.
We recently upgraded OpenSSL from version 1.1.1 to 3.4.0. After this upgrade, we observed that PKCS#12 files generated using OpenSSL 3.4.0 fail to import into the macOS Keychain with the following error:
Failed to import PKCS#12 data: -25264
(MAC verification failed during PKCS12 import (wrong password?))
This issue is reproducible on macOS 14.8.2. The same PKCS#12 files import successfully on other macOS versions, including 15.x and 26.x.
Additionally, PKCS#12 files that fail to import on macOS 14.8 work correctly when copied and imported on other macOS versions without any errors.
PKCS#12 Creation
The PKCS#12 data is created using the following OpenSSL API:
const char* platformPKCS12SecureKey =
_platformSecureKey.has_value() ? _platformSecureKey.value().c_str() : NULL;
PKCS12* p12 = PKCS12_create(
platformPKCS12SecureKey,
NULL,
keys,
_cert,
NULL,
0, 0, 0, 0, 0
);
if (!p12)
{
throw std::runtime_error("Failed to create PKCS#12 container");
}
PKCS#12 Import
The generated PKCS#12 data is imported into the macOS Keychain using the following code:
NSString *certPassKey = [NSString stringWithUTF8String:getCertPassKey()];
NSDictionary *options = @{
(__bridge id)kSecImportExportPassphrase: certPassKey,
(__bridge id)kSecAttrAccessible:
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
(__bridge id)kSecAttrIsExtractable: @YES,
(__bridge id)kSecAttrIsPermanent: @YES,
(__bridge id)kSecAttrAccessGroup: APP_GROUP
};
CFArrayRef items = NULL;
OSStatus status = SecPKCS12Import(
(__bridge CFDataRef)pkcs12Data,
(__bridge CFDictionaryRef)options,
&items
);
Topic:
Privacy & Security
SubTopic:
General
Tags:
macOS
Signing Certificates
iCloud Keychain Verification Codes
Passkeys in iCloud Keychain
Hello,
I am developing a macOS menu bar window-management utility (similar in functionality to Magnet / Rectangle) that relies on the Accessibility (AXUIElement) API to move and resize windows and on global hotkeys.
I am facing a consistent issue when App Sandbox is enabled.
Summary:
App Sandbox enabled
Hardened Runtime enabled
Apple Events entitlement enabled
NSAccessibilityDescription present in Info.plist
AXIsProcessTrustedWithOptions is called with prompt enabled
Observed behavior:
When App Sandbox is enabled, the Accessibility permission prompt never appears.
The app cannot be manually added in System Settings → Privacy & Security → Accessibility.
AXIsProcessTrusted always returns false.
As a result, window snapping does not work.
When App Sandbox is disabled:
The Accessibility prompt appears correctly.
The app functions as expected.
This behavior occurs both:
In local builds
In TestFlight builds
My questions:
Is this expected behavior for sandboxed macOS apps that rely on Accessibility APIs?
Are window-management utilities expected to ship without App Sandbox enabled?
Is there any supported entitlement or configuration that allows a sandboxed app to request Accessibility permission?
Thank you for any clarification.
During internal testing, we observed the following behavior and would appreciate clarification on whether it is expected and supported in production environments.
When generating an elliptic-curve cryptographic key pair using "kSecAttrTokenIDSecureEnclave", and explicitly specifying a "kSecAttrAccessGroup", we found that cryptographic operations (specifically encryption and decryption) could be successfully performed using this key pair from two distinct applications. Both applications had the Keychain Sharing capability enabled and were signed with the same provisioning profile identity.
Given the documented security properties of Secure Enclave, backed keys, namely that private key material is protected by hardware and access is strictly constrained by design, we would like to confirm whether the ability for multiple applications (sharing the same keychain access group and signing identity) to perform cryptographic operations with the same Secure Enclave–backed key is expected behavior on iOS.
Specifically, we are seeking confirmation on:
Whether this behavior is intentional and supported in production.
Whether the Secure Enclave enforces access control primarily at the application-identifier (App ID) level rather than the individual app bundle level in this scenario.
Whether there are any documented limitations or guarantees regarding cross-application usage of Secure Enclave keys when keychain sharing is configured.
Any guidance or references to official documentation clarifying this behavior would be greatly appreciated.
Topic:
Privacy & Security
SubTopic:
General