Skip to content

Conversation

@mikma
Copy link
Contributor

@mikma mikma commented May 23, 2025

This draft PR adds an NFC transport with two backends: PC/SC and libnfc. The backends are enabled using features: pcsc and libnfc.

The NFC transport is not complete yet, support for ctap1 is missing, and also support for NFCCTAP_GETRESPONSE, which seems to be optional.

When finished this PR should fix #5.

I have tested the transport with two NFC readers:

  • DFRobot NFC module based on PN532 and connected to a USB to serial adapter and supported by libnfc.
  • ACR122U-A9 with PC/SC driver (libacsccid1).

And I have used the USB-C Titan Security Key (K52T) with both readers.

What do you think?

@AlfioEmanueleFresta
Copy link
Member

AlfioEmanueleFresta commented May 23, 2025

Thank you for your work @mikma, this is incredible. I'll make sure to review this over the next few days.

As for testing, I have an ACR122U and a bunch of NFC keys to throw into the bunch - but I won't have access to them until Tue/Wed.

Copy link
Member

@AlfioEmanueleFresta AlfioEmanueleFresta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work so far @mikma!

Please consider adding an example script & updating the README. I'll be able to test with my ACR122U and a few more keys once we have an example script :)

const APDU_FIDO: &[u8; 8] = b"\xa0\x00\x00\x06\x47\x2f\x00\x01";
const SW1_MORE_DATA: u8 = 0x61;

#[derive(thiserror::Error)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call here, I did this more widely in #107.

Apdu(#[from] apdu::Error),

/// Unexpected error occurred on the device.
Device(Box<dyn Display>),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this is only used with HandleError which implements Error. Can we use #[from] HandleError here? We could then derive Debug, Display,

}
}

impl From<NfcError> for Error {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this once #107 lands

command: &[u8],
response: &mut [u8],
) -> apdu_core::Result {
trace!("TX: {:?}", command);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Prefer using fields for structured logging, if possible.

trace!(?command, "TX")

AlfioEmanueleFresta added a commit that referenced this pull request May 26, 2025
* Reduces some boilerplate
* Used in #105 - allow making dependency non-optional, rather than for
`nfc` feature only
* I plan to use this in new CBOR serialization and deserialization, as I
would like to encapsulate underlying errors (more easily)

const SELECT_P1: u8 = 0x04;
const SELECT_P2: u8 = 0x00;
const APDU_FIDO: &[u8; 8] = b"\xa0\x00\x00\x06\x47\x2f\x00\x01";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is AID, not APDU


#[instrument]
pub fn list_devices() -> Result<Vec<NfcDevice>, Error> {
let ctx = pcsc::Context::establish(pcsc::Scope::User).expect("PC/SC context");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlfioEmanueleFresta AlfioEmanueleFresta added the help wanted Extra attention is needed label Jul 13, 2025
@AlfioEmanueleFresta
Copy link
Member

Hi @mikma, friendly ping on the above. If you're unable to address the comments at this point that's totally fine - another contributor has expressed interest in picking this up. It'd be a pity not to merge this! TIA :)

@mikma
Copy link
Contributor Author

mikma commented Sep 30, 2025

Yes, let someone else pick up, that's fine.

I pushed some changes in order for the branch to build.

(I also added a branch with some experimental code which detects that the user places the NFC tag on the reader. Something like that is needed to test for user presence I think. https://github.com/mikma/libwebauthn/tree/nfc-wait-on-device)

@msirringhaus msirringhaus mentioned this pull request Oct 1, 2025
AlfioEmanueleFresta pushed a commit that referenced this pull request Oct 29, 2025
Very heavily based on #105, with the following additions: 

- Fleshed out the APDU-calls
- Added `select_fido2()` to discover both U2F and FIDO2-only devices
- Made `NfcDevice` derive `Clone` and other minor tweaks, so we can
easily use it in `credentialsd`
- Added the build with both NFC-features to the github CI (including the
installation of libnfc et al.). I kept this separate from the original,
un-featured build, so we can be sure the former works even without
libnfc installed.

Open questions:
- Biggest question to me is, how to handle the multiple backends and
multiple devices. Since we can't run the "blink and wait for user
presence"-scheme with NFC as we do with USB, I'm leaning towards simply
always returning the very first found NFC-device instead of a list of
found devices and use that. With this, we could get rid of the
duplication-problem. I'm not sure many setups would include more than
one NFC-reader (with different devices on there).
- The cancel-handle is currently unused, and I'm not sure if we can use
it anywhere at all.
- No testing yet. Not sure how easy that would be to add.
- Given that `credentialsd` uses a poll-mechanism to find USB-devices
(simply looping over `list_devices()`) as well, I did not investigate to
get a blocking device discovery.
- For testing, I hacked my local credentialsd-repo by simply replacing
`hid` with `nfc` in the USB-handler. Thus, I needed a dummy
`blink_and_wait_for_user_presence()`-implementation. This should
probably be removed, esp. if we go for the "return first device"-scheme
mentioned above. But doing that, I was able to successfully use
NFC-devices with Firefox.

---------

Co-authored-by: Mikael Magnusson <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

help wanted Extra attention is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FIDO2: Near-Field Communication (NFC) support

3 participants