How to communicate with smart card readers conncetd to USB-C port in iOS?

Hello All,

I am new to iOS development and would like to detect the smart card readers connected to USB-C port on iOS (16+) devices. The smart card reader is a custom hardware and not MFi certified. So as per my understanding, I cannot use ExternalAccessory.framework without MFi certification. Correct?

How else can I achieve this? Does TKSmartCardSlotManager works for this purpose (or is it only for NFC devices?)? Is there any example for how to use this interface? I couldn't find any example for this as a starting point...

Thanks in advance.

iOS does not have a mechanism for third-party code to talk to generic USB devices [1].

The smart card reader is a custom hardware and not MFi certified. So as per my understanding, I cannot use ExternalAccessory.framework without MFi certification.

True. But even if that were possible, it’s not easy to use EA framework from a CTK appex.

iOS has built-in support for standard USB smart cards (via USB CCID), so the easiest way to achieve your goal is to change your hardware to support that standard.

Share and Enjoy

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

[1] iPadOS can do this with DriverKit, but that one of a small set of iPadOS-specific facilities that aren’t on iOS.

Hi  @eskimo , thanks for the update.

iOS has built-in support for standard USB smart cards (via USB CCID), so the easiest way to achieve your goal is to change your hardware to support that standard.

This is interesting. The hardware has USB CCID. Should we use TKSmartCardSlotManager for this? I wrote a basic swift file using TKSmartCardSlotManager

import CryptoTokenKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // Start observing smart card slot state changes
        startObservingSmartCardSlotStateChanges()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // Stop observing smart card slot state changes when the view disappears
        stopObservingSmartCardSlotStateChanges()
    }

    func startObservingSmartCardSlotStateChanges() {
        DispatchQueue.global().async {
            if let slotManager = TKSmartCardSlotManager.default {
                while true {
                    let slotNames = slotManager.slotNames // No need for optional binding
                    
                    for reader in slotNames {
                        slotManager.getSlot(withName: reader) { slot in
                            guard let slot = slot else {
                                print("Slot for reader \(reader) is nil")
                                return
                            }
                            
                            let state = slot.state
                            if state.contains(.cardPresent) {
                                // Smart card is present in the slot
                                print("Smart card is present in slot: \(reader)")
                                
                                // Example: Communicate with the smart card
                                if let card = slot.makeSmartCard() {
                                    card.beginSession { session, error in
                                        if let error = error {
                                            print("Error beginning session with smart card: \(error.localizedDescription)")
                                            return
                                        }
                                        // Session started, now you can communicate with the smart card
                                    }
                                }
                            } else if state.contains(.empty) {
                                // Smart card slot is empty
                                print("Smart card slot is empty: \(reader)")
                            } else {
                                // Unknown state or other state
                                print("Smart card slot is in an unknown state: \(reader)")
                            }
                        }
                    }
                    
                    // Poll every few seconds
                    sleep(5)
                }
            } else {
                // Handle the case where 'default' returns nil
                print("TKSmartCardSlotManager.default is nil")
            }
        }
    }

    func stopObservingSmartCardSlotStateChanges() {
    }
}

Do you think this is correct implementation? Your feedback would be helpful

Thanks in advance

Hello @DTS Engineer , do you have any updates for me on this topic? It would be great to know your feedback

Should we use TKSmartCardSlotManager for this?

It depends on what your actual goals are:

  • If you only want to sign or decrypt data using the digital identities stored on tokens, you don’t need to use CryptoTokenKit at all. You can find and use token-based digital identities using just Security framework APIs.

  • If you want to do more sophisticated things with smart cards, you can use CryptoTokenKit APIs for that purpose.

For example, I have a smart card signing test project where the vast bulk of the code is based on Security framework, but I use TKTokenWatcher to learn about smart cards coming and going so that I can update my UI.

Do you think this is correct implementation?

It’s hard to offer a big-picture opinion without knowing what your specific goals are.

However, there’s one obvious small-picture problem: You’re using a Dispatch global concurrent queue. This is a bad idea in general — see Avoid Dispatch Global Concurrent Queues — but it’s particularly bad here because you’re permanently tying down one of Dispatch’s limited number of worker threads.

A better way to listen for changes in the token setup is with the TKTokenWatcher class. And for smart cards specifically, you can use KVO to observe:

Share and Enjoy

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

How to communicate with smart card readers conncetd to USB-C port in iOS?
 
 
Q