FIDO2 USB Monitoring using custom Authorization Plugin

I'm looking to implement USB monitoring for FIDO2 authentication through a custom Authorization Plugin, specifically for the below ones.

This plugin applies to the following macOS authorization mechanisms:

  • system.login.console — login window authentication
  • system.login.screensaver — screensaver unlock authentication

The goal is to build a GUI AuthPlugin, an authorization plugin that presents a custom window prompting the user to "Insert your FIDO key”. Additionally, the plugin should detect when the FIDO2 device is removed and respond accordingly.

Additional Info: We have already developed a custom authorization plugin which is a primary authentication using OTP at login and Lock Screen. We are now extending to include FIDO2 support as a primary.

Our custom authorization plugin is designed to replace the default loginwindow:login mechanism with a custom implementation.

Question: Is there a reliable approach to achieve the USB monitoring functionality through a custom authorization plugin? Any guidance or pointers on this would be greatly appreciated.

Answered by DTS Engineer in 864964022
I’m looking for USB monitoring code that can function within an authorization plugin

It’s hard to be sure without testing it, but I believe that our standard USB APIs will work in the authorisation plug-in context.

My standard advice here applies: Get things working from a test app and then move that code into your authorisation plug-in. That way you’re only debugging one thing at a time.

Oh, and our USB APIs are somewhat confusing:

  • The modern API is the IOUSBHost framework.
  • You’ll find lots of references to IOUSBHost is the Kernel framework. Ignore those. They are only relevant to KEXTs.
  • You can also find USB APIs in the IOKit framework. Those are deprecated in favour of IOUSBHost framework.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I’m not sure I understand the concern here:

  • Are you asking about how to interact with this FIDO2 USB device?
  • Or whether that code will work in an authorisation plug-in?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Many thanks for getting back to me.

Or whether that code will work in an authorisation plug-in?

I’m looking for USB monitoring code that can function within an authorization plugin, specifically, a custom GUI AuthPlugin window that displays prompts when a FIDO key is inserted or removed.

I’m looking for USB monitoring code that can function within an authorization plugin

It’s hard to be sure without testing it, but I believe that our standard USB APIs will work in the authorisation plug-in context.

My standard advice here applies: Get things working from a test app and then move that code into your authorisation plug-in. That way you’re only debugging one thing at a time.

Oh, and our USB APIs are somewhat confusing:

  • The modern API is the IOUSBHost framework.
  • You’ll find lots of references to IOUSBHost is the Kernel framework. Ignore those. They are only relevant to KEXTs.
  • You can also find USB APIs in the IOKit framework. Those are deprecated in favour of IOUSBHost framework.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks again for your inputs.

Yes, I started with a test app, and it worked as expected. Then I moved on to the authorization plugin, where the detection part isn’t behaving as expected.

I later thought of checking with Apple in case there’s any limitation around the monitoring part within securityd.

I’ll review it again based on your suggestions to see if I missed anything.

I moved on to the authorization plugin, where the detection part isn’t behaving as expected.

Hmmm, interesting. I wish you’d shared that detail up front.

The most common gotcha in situations like this is that the resource has some sort of privacy gate. I see this, for example, with Bluetooth. I don’t think that’s the case for USB, but I’m checking with a colleague about that.

Presuming that’s not it, the next thing I’d check in the run loop. Depends on the era of the API you’re using, it may implicitly schedule stuff on the run loop. That can cause problems for plug-ins because you can’t guarantee that the run loop is running.

Which API are you using to set up your USB device detection callbacks?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you!

The APIs listed below are utilized to identify FIDO HID devices exclusively, with their corresponding callback registration functions shown here.

        // Match only FIDO HID devices
        let matchingDict: [String: Any] = [
            kIOHIDDeviceUsagePageKey as String: 0xF1D0
        ]
        IOHIDManagerSetDeviceMatching(mgr, matchingDict as CFDictionary)

        // Register callbacks
        IOHIDManagerRegisterDeviceMatchingCallback(mgr, deviceAddedCallback, UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()))
        IOHIDManagerRegisterDeviceRemovalCallback(mgr, deviceRemovedCallback, UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()))

        // Schedule with current run loop
        IOHIDManagerScheduleWithRunLoop(mgr, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)

        let result = IOHIDManagerOpen(mgr, IOOptionBits(kIOHIDOptionsTypeNone))

Randomly it crashes at runloop

Terminating Process:   SecurityAgentHelper-arm64 [2303]

Application Specific Information:
abort() called


Thread 0::  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	       0x1883c9c34 mach_msg2_trap + 8
1   libsystem_kernel.dylib        	       0x1883dc3a0 mach_msg2_internal + 76
2   libsystem_kernel.dylib        	       0x1883d2764 mach_msg_overwrite + 484
3   libsystem_kernel.dylib        	       0x1883c9fa8 mach_msg + 24
4   CoreFoundation                	       0x1884f6cbc __CFRunLoopServiceMachPort + 160
5   CoreFoundation                	       0x1884f55d8 __CFRunLoopRun + 1208
6   CoreFoundation                	       0x1884f4a98 CFRunLoopRunSpecific + 572
7   HIToolbox                     	       0x193f9727c RunCurrentEventLoopInMode + 324
8   HIToolbox                     	       0x193f9a4e8 ReceiveNextEventCommon + 676
9   HIToolbox                     	       0x194125484 _BlockUntilNextEventMatchingListInModeWithFilter + 76

I’m able to perform FIDO authentication with the key inserted via USB randomly crashes most of the time crash log shows runloop;

however, NFC-based authentication does not work (NFC-over-HID devices (OMNIKEY):

communication with ctkpcscd failed

Could you please share any inputs

Randomly it crashes at runloop

Please post the full crash report. See Posting a Crash Report for advice on how to do that.

The crash report snippet you posted indicated that the main thread isn’t the thread that crashed. It’s blocked in the run loop. Some other thread is likely to have called abort, and the full crash report should give me an idea as to what’s going on.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for your time and input.

After making a few code changes, everything started working. I’ve moved the monitoring logic into an XPC daemon, and things are functioning as expected.

FIDO2 USB Monitoring using custom Authorization Plugin
 
 
Q