Post

Replies

Boosts

Views

Activity

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:
3w
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:
4w
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:
4w
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