Post

Replies

Boosts

Views

Activity

Reply to SFAuthorizationPluginView password field does not accept keyboard input until click on macOS Tahoe 26.4.1
We are also facing this issue. To reproduce it, you don’t even need an authorization plugin; it is sufficient to replace use-login-window-ui with authenticate-session-owner in system.login.screensaver rule. On macOS 26.3 and prior, the window “You must enter a password to unlock the screen” is the key window, the password text field is focused, and you can enter the password and press Return to unlock or press Esc to dismiss the window. On macOS 26.4, 26.4.1, and 26.5 Beta 4, that window is no longer the key window, the password text field is not in focus, and pressing Return or Esc does nothing. I filed a feedback on an unrelated issue which also involved changing use-login-window-ui to authenticate-session-owner (FB22289735) and Apple said that this is unsupported configuration, but even then, surely this issue is a regression that should be addressed? I must say that with the number of issues it caused (Calling SecKeychainUnlock with a locked keychain and an invalid password returns errSecSuccess on macOS 26.4/FB22627354; FB22657681 — a PAM module breaking the keychain, which took some three weeks of digging; the lock screen being shown up twice — we have that too, by the way; this issue), macOS 26.4 has been damaging to our product.
Topic: Privacy & Security SubTopic: General Tags:
May ’26
Reply to Calling SecKeychainUnlock with a locked keychain and an invalid password returns errSecSuccess on macOS 26.4
Thanks Quinn, I created an enhancement request as you suggested: FB2491408. I have one more question. When I launch Keychain Access and type in an incorrect password, the app doesn’t accept it and shakes the window. Does it mean that Keychain Access is using some other private API that we are not allowed to use? Also, I understand that it’s a case of xkcd comic “Workflow” and that SecKeychainUnlock is deprecated, but it would still be nice to have a heads-up before such changes are deployed, especially since there is no alternative API.
Topic: Privacy & Security SubTopic: General Tags:
Apr ’26
Reply to Calling SecKeychainUnlock with a locked keychain and an invalid password returns errSecSuccess on macOS 26.4
Thank you for clarifying that it is intended. It is a part of a passwordless authentication product. We’re changing user’s password from a privileged security agent plugin. We’re using ODRecord’s changePassword(_:toPassword:) to do that. We’re using SecKeychainChangePassword to change the keychain password. Confirming the login keychain via SecKeychainUnlock is an old code which I assume was added to avoid calling SecKeychainChangePassword unnecessarily.
Topic: Privacy & Security SubTopic: General Tags:
Apr ’26
Reply to Get identities from a smart card in an authorization plugin
Thank you very much for your assistance Quinn. In a non-privileged plugin, I was able to read the certificate from my Yubikey in both system.login.console and authenticate rights with this code: CFTypeRef watcherRef = nil; OSStatus status = [mPluginRef engineCallback]->GetTKTokenWatcher(mEngineRef, &watcherRef); if (status) { os_log(OS_LOG_DEFAULT, "Error fetching token watcher: %{public}@\n", SecCopyErrorMessageString(status, nil)); return; } TKTokenWatcher *watcher = (TKTokenWatcher *)watcherRef; [watcher setInsertionHandler:^(NSString * _Nonnull tokenID) { if (![tokenID containsString:@"pivtoken"]) return; os_log(OS_LOG_DEFAULT, "Inserted token: %{public}@\n", tokenID); CFTypeRef ctx = nil; OSStatus status = [mPluginRef engineCallback]->GetLAContext(mEngineRef, &ctx); if (status) { os_log(OS_LOG_DEFAULT, "Error fetching context: %{public}@\n", SecCopyErrorMessageString(status, nil)); return; } CFArrayRef identities = nil; status = [mPluginRef engineCallback]->GetTokenIdentities(mEngineRef, ctx, &identities); if (status) { os_log(OS_LOG_DEFAULT, "Error fetching identities: %{public}@\n", SecCopyErrorMessageString(status, nil)); return; } for (CFIndex idx = 0; idx < CFArrayGetCount(identities); idx++) { CFTypeRef identityArray = CFArrayGetValueAtIndex(identities, idx); if (CFGetTypeID(identityArray) != CFArrayGetTypeID() || !CFArrayGetCount(identityArray)) continue; CFTypeRef identityRef = CFArrayGetValueAtIndex(identityArray, 0); if (CFGetTypeID(identityRef) != SecIdentityGetTypeID()) continue; SecIdentityRef identity = (SecIdentityRef)identityRef; SecKeyRef privateKey = nil; status = SecIdentityCopyPrivateKey(identity, &privateKey); if (status) { os_log(OS_LOG_DEFAULT, "Error fetcing private key: %{public}@\n", SecCopyErrorMessageString(status, nil)); continue; } NSDictionary *attrs = (__bridge NSDictionary *)SecKeyCopyAttributes(privateKey); id tkid = [attrs objectForKey:@"tkid"]; if (!tkid || ![tkid isKindOfClass:[NSString class]] || ![tokenID isEqualToString:(NSString *)tkid]) continue; SecCertificateRef certificate = nil; status = SecIdentityCopyCertificate(identity, &certificate); if (status) { os_log(OS_LOG_DEFAULT, "Error fetching certificate: %{public}@\n", SecCopyErrorMessageString(status, nil)); continue; } os_log(OS_LOG_DEFAULT, "Fetched certificate: %{public}@\n", certificate); } }]; Here is the output: Inserted token: com.apple.pivtoken:<redacted> Fetched certificate: <cert(0x8c4ea1e00) s: Yubico Authentication i: Yubico Authentication> Curiously, this also seems to work when I create watcher with [TKTokenWatcher new]. I assume it is still preferable to use GetTKTokenWatcher. In a privileged plugin, this code fails to fetch identities with errAuthorizationDenied, but I think I can live with that.
Topic: Privacy & Security SubTopic: General Tags:
Jan ’26
Reply to Get identities from a smart card in an authorization plugin
Thanks, I have opened a support request like you suggested. I want to clarify that I'm using NameAndPassword solely because it provides a convenient scaffolding for an authorization plugin and it is much quicker to iterate with it than with my actual plugin (think 10-20 seconds versus 3+ minutes per attempt). Still, I did test the same code in the latter, and I also went through your steps, all with the same results.
Topic: Privacy & Security SubTopic: General Tags:
Jan ’26
Reply to Get identities from a smart card in an authorization plugin
Yes, here's a full log (I replaced the bundle ID and redacted the token hash): $ log stream --predicate 'subsystem = "com.example.NameAndPassword"' --style compact Filtering the log data using "subsystem ==[cd] "com.example.NameAndPassword"" Timestamp Ty Process[PID:TID] 2026-01-15 20:41:18.941 Df SecurityAgentHelper-arm64[11135:3f6df] [com.example.NameAndPassword:AuthPlugin] Inserted token: com.apple.pivtoken:<redacted> 2026-01-15 20:41:18.951 Df SecurityAgentHelper-arm64[11135:3f6df] [com.example.NameAndPassword:AuthPlugin] Found identities: 1 2026-01-15 20:41:25.722 Df SecurityAgentHelper-arm64[11164:3f7db] [com.example.NameAndPassword:AuthPlugin] Inserted token: com.apple.pivtoken:<redacted> 2026-01-15 20:41:25.723 Df SecurityAgentHelper-arm64[11164:3f7db] [com.example.NameAndPassword:AuthPlugin] Error: -25291
Topic: Privacy & Security SubTopic: General Tags:
Jan ’26
Reply to Get identities from a smart card in an authorization plugin
Thanks for the suggestions. I successfully paired my Yubikey with sc_auth pair. After a restart, on the FileVault screen, I got a prompt to enter a PIN. When I did, I got an error "Smartcard configuration is invalid for this account" (I assume because I didn't do sc_auth filevault enable), so I had to unlock FileVault with my password. After that, the smart card worked normally: I was able to log out and then log back in with the PIN. So I have to assume my Yubikey works. I then did sc_unpair and proceeded to test the kSecAttrAccessGroupToken theory. I modified my code like this: TKTokenWatcher *watcher = [TKTokenWatcher new]; [watcher setInsertionHandler:^(NSString *tokenID) { if (![tokenID containsString:@"pivtoken"]) return; os_log(OS_LOG_DEFAULT, "Inserted token: %{public}@\n", tokenID); [watcher addRemovalHandler:^(NSString *tokenID) { os_log(OS_LOG_DEFAULT, "Removed token: %{public}@\n", tokenID); } forTokenID:tokenID]; CFArrayRef identities = nil; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecMatchLimit: (id)kSecMatchLimitAll, (id)kSecReturnRef: @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, (id)kSecAttrTokenID: tokenID, }, (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); } }]; It works fine in the authenticate right, no matter whether I run security authorize -u authenticate or go to the System Settings and mess with the checkboxes (I removed irrelevant parts from the log): Inserted token: com.apple.pivtoken:<redacted> Found identities: 1 However, I get errSecNotAvailable error in the system.login.console right: Inserted token: com.apple.pivtoken:<redacted> Error: -25291 The mechanism is registered as non-privileged in both cases. Does this means that the App ID entitlement is required?
Topic: Privacy & Security SubTopic: General Tags:
Jan ’26
Reply to SFAuthorizationPluginView password field does not accept keyboard input until click on macOS Tahoe 26.4.1
We are also facing this issue. To reproduce it, you don’t even need an authorization plugin; it is sufficient to replace use-login-window-ui with authenticate-session-owner in system.login.screensaver rule. On macOS 26.3 and prior, the window “You must enter a password to unlock the screen” is the key window, the password text field is focused, and you can enter the password and press Return to unlock or press Esc to dismiss the window. On macOS 26.4, 26.4.1, and 26.5 Beta 4, that window is no longer the key window, the password text field is not in focus, and pressing Return or Esc does nothing. I filed a feedback on an unrelated issue which also involved changing use-login-window-ui to authenticate-session-owner (FB22289735) and Apple said that this is unsupported configuration, but even then, surely this issue is a regression that should be addressed? I must say that with the number of issues it caused (Calling SecKeychainUnlock with a locked keychain and an invalid password returns errSecSuccess on macOS 26.4/FB22627354; FB22657681 — a PAM module breaking the keychain, which took some three weeks of digging; the lock screen being shown up twice — we have that too, by the way; this issue), macOS 26.4 has been damaging to our product.
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
May ’26
Reply to Calling SecKeychainUnlock with a locked keychain and an invalid password returns errSecSuccess on macOS 26.4
Thanks Quinn, I created an enhancement request as you suggested: FB2491408. I have one more question. When I launch Keychain Access and type in an incorrect password, the app doesn’t accept it and shakes the window. Does it mean that Keychain Access is using some other private API that we are not allowed to use? Also, I understand that it’s a case of xkcd comic “Workflow” and that SecKeychainUnlock is deprecated, but it would still be nice to have a heads-up before such changes are deployed, especially since there is no alternative API.
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
Apr ’26
Reply to Calling SecKeychainUnlock with a locked keychain and an invalid password returns errSecSuccess on macOS 26.4
Thank you for clarifying that it is intended. It is a part of a passwordless authentication product. We’re changing user’s password from a privileged security agent plugin. We’re using ODRecord’s changePassword(_:toPassword:) to do that. We’re using SecKeychainChangePassword to change the keychain password. Confirming the login keychain via SecKeychainUnlock is an old code which I assume was added to avoid calling SecKeychainChangePassword unnecessarily.
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
Apr ’26
Reply to Unlock with Touch ID suggested despite system.login.screensaver being configured with authenticate-session-owner rule
Thanks Quinn, I have filed a bug report: FB22289735.
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
Mar ’26
Reply to Get identities from a smart card in an authorization plugin
Thank you very much for your assistance Quinn. In a non-privileged plugin, I was able to read the certificate from my Yubikey in both system.login.console and authenticate rights with this code: CFTypeRef watcherRef = nil; OSStatus status = [mPluginRef engineCallback]->GetTKTokenWatcher(mEngineRef, &watcherRef); if (status) { os_log(OS_LOG_DEFAULT, "Error fetching token watcher: %{public}@\n", SecCopyErrorMessageString(status, nil)); return; } TKTokenWatcher *watcher = (TKTokenWatcher *)watcherRef; [watcher setInsertionHandler:^(NSString * _Nonnull tokenID) { if (![tokenID containsString:@"pivtoken"]) return; os_log(OS_LOG_DEFAULT, "Inserted token: %{public}@\n", tokenID); CFTypeRef ctx = nil; OSStatus status = [mPluginRef engineCallback]->GetLAContext(mEngineRef, &ctx); if (status) { os_log(OS_LOG_DEFAULT, "Error fetching context: %{public}@\n", SecCopyErrorMessageString(status, nil)); return; } CFArrayRef identities = nil; status = [mPluginRef engineCallback]->GetTokenIdentities(mEngineRef, ctx, &identities); if (status) { os_log(OS_LOG_DEFAULT, "Error fetching identities: %{public}@\n", SecCopyErrorMessageString(status, nil)); return; } for (CFIndex idx = 0; idx < CFArrayGetCount(identities); idx++) { CFTypeRef identityArray = CFArrayGetValueAtIndex(identities, idx); if (CFGetTypeID(identityArray) != CFArrayGetTypeID() || !CFArrayGetCount(identityArray)) continue; CFTypeRef identityRef = CFArrayGetValueAtIndex(identityArray, 0); if (CFGetTypeID(identityRef) != SecIdentityGetTypeID()) continue; SecIdentityRef identity = (SecIdentityRef)identityRef; SecKeyRef privateKey = nil; status = SecIdentityCopyPrivateKey(identity, &privateKey); if (status) { os_log(OS_LOG_DEFAULT, "Error fetcing private key: %{public}@\n", SecCopyErrorMessageString(status, nil)); continue; } NSDictionary *attrs = (__bridge NSDictionary *)SecKeyCopyAttributes(privateKey); id tkid = [attrs objectForKey:@"tkid"]; if (!tkid || ![tkid isKindOfClass:[NSString class]] || ![tokenID isEqualToString:(NSString *)tkid]) continue; SecCertificateRef certificate = nil; status = SecIdentityCopyCertificate(identity, &certificate); if (status) { os_log(OS_LOG_DEFAULT, "Error fetching certificate: %{public}@\n", SecCopyErrorMessageString(status, nil)); continue; } os_log(OS_LOG_DEFAULT, "Fetched certificate: %{public}@\n", certificate); } }]; Here is the output: Inserted token: com.apple.pivtoken:<redacted> Fetched certificate: <cert(0x8c4ea1e00) s: Yubico Authentication i: Yubico Authentication> Curiously, this also seems to work when I create watcher with [TKTokenWatcher new]. I assume it is still preferable to use GetTKTokenWatcher. In a privileged plugin, this code fails to fetch identities with errAuthorizationDenied, but I think I can live with that.
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26
Reply to Get identities from a smart card in an authorization plugin
Thanks, I have opened a support request like you suggested. I want to clarify that I'm using NameAndPassword solely because it provides a convenient scaffolding for an authorization plugin and it is much quicker to iterate with it than with my actual plugin (think 10-20 seconds versus 3+ minutes per attempt). Still, I did test the same code in the latter, and I also went through your steps, all with the same results.
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26
Reply to Get identities from a smart card in an authorization plugin
Yes, here's a full log (I replaced the bundle ID and redacted the token hash): $ log stream --predicate 'subsystem = "com.example.NameAndPassword"' --style compact Filtering the log data using "subsystem ==[cd] "com.example.NameAndPassword"" Timestamp Ty Process[PID:TID] 2026-01-15 20:41:18.941 Df SecurityAgentHelper-arm64[11135:3f6df] [com.example.NameAndPassword:AuthPlugin] Inserted token: com.apple.pivtoken:<redacted> 2026-01-15 20:41:18.951 Df SecurityAgentHelper-arm64[11135:3f6df] [com.example.NameAndPassword:AuthPlugin] Found identities: 1 2026-01-15 20:41:25.722 Df SecurityAgentHelper-arm64[11164:3f7db] [com.example.NameAndPassword:AuthPlugin] Inserted token: com.apple.pivtoken:<redacted> 2026-01-15 20:41:25.723 Df SecurityAgentHelper-arm64[11164:3f7db] [com.example.NameAndPassword:AuthPlugin] Error: -25291
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26
Reply to Get identities from a smart card in an authorization plugin
Thanks for the suggestions. I successfully paired my Yubikey with sc_auth pair. After a restart, on the FileVault screen, I got a prompt to enter a PIN. When I did, I got an error "Smartcard configuration is invalid for this account" (I assume because I didn't do sc_auth filevault enable), so I had to unlock FileVault with my password. After that, the smart card worked normally: I was able to log out and then log back in with the PIN. So I have to assume my Yubikey works. I then did sc_unpair and proceeded to test the kSecAttrAccessGroupToken theory. I modified my code like this: TKTokenWatcher *watcher = [TKTokenWatcher new]; [watcher setInsertionHandler:^(NSString *tokenID) { if (![tokenID containsString:@"pivtoken"]) return; os_log(OS_LOG_DEFAULT, "Inserted token: %{public}@\n", tokenID); [watcher addRemovalHandler:^(NSString *tokenID) { os_log(OS_LOG_DEFAULT, "Removed token: %{public}@\n", tokenID); } forTokenID:tokenID]; CFArrayRef identities = nil; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecMatchLimit: (id)kSecMatchLimitAll, (id)kSecReturnRef: @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, (id)kSecAttrTokenID: tokenID, }, (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); } }]; It works fine in the authenticate right, no matter whether I run security authorize -u authenticate or go to the System Settings and mess with the checkboxes (I removed irrelevant parts from the log): Inserted token: com.apple.pivtoken:<redacted> Found identities: 1 However, I get errSecNotAvailable error in the system.login.console right: Inserted token: com.apple.pivtoken:<redacted> Error: -25291 The mechanism is registered as non-privileged in both cases. Does this means that the App ID entitlement is required?
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26
Reply to Get identities from a smart card in an authorization plugin
I have a mechanism that provides UI by subclassing SFAuthorizationPluginView and a privileged mechanism that performs the authorization. I tried reading Yubikey identities in both of them and at various points, with no luck.
Topic: Privacy & Security SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26