Add U2F over NFC support#543
Conversation
|
This seems like a surprisingly small diff for what imo one would expect to be a large feature that took so long for someone to get working (first attempt was like 4 years ago). If it actually works, impressive work. Will try out later today, thanks for the PR |
|
i cant seem to get this to work. im using https://webauthn.io on an iphone 12. what are you testing with? |
|
I have only tested on android. It would be great if you take some logs but I can also test with an iPhone later. |
|
@asaldele1 i might have an idea of what is going on. |
|
or maybe not, |
|
wrt that, have a look here bettse/seos_compatible#4 i made bettse's app support both momentum's and ofw's version of |
|
No, I assume that PCB is handled by the firmware. I think it wouldn't work on android either if i didn't. The first byte is CLA. |
|
Yea, I know about this PR. In the app I check it like it's done in the seos app. |
|
I mean asaldele1/u2f_over_nfc |
|
ahh i see, very nice :) |
|
i added a log for the full APDU: |
|
i notice something interesting here. this really reminds me of how mifare desfire and mifare plus ev do their apdu's. they support both a single byte legacy mifare style command, or can wrap these commands in basic apdu format using CLA 0x90. |
|
I think the problem is that the phone is checking the token for compatibility with Apple Pay protocols. We should be returning 'Instruction Not Supported' (6D00), but we are returning 'Conditions Not Satisfied' (6985). We need to validate the command before checking whether the applet has been selected. |
https://www.cardlogix.com/wp-content/uploads/MIFARE-Application-Programming-Guide-for-DESFfire_rev.e.pdf this says that INS 0x60 here means "Get File Buffer Addr." and has no additional data. not sure why, but its a real command and the format checks out, so seems like its trying to talk to a desfire / mifare plus ev card lol |
|
still nothing sadly: diff --git a/applications/main/u2f/u2f_nfc.c b/applications/main/u2f/u2f_nfc.c
index 404ae2d590..f4f2760c6d 100644
--- a/applications/main/u2f/u2f_nfc.c
+++ b/applications/main/u2f/u2f_nfc.c
@@ -16,10 +16,10 @@
#define U2F_NFC_PAYLOAD_SIZE 960
#define U2F_NFC_TX_BUFFER_SIZE 480
-#define U2F_SW_CONDITIONS_NOT_SATISFIED_1 0x69
-#define U2F_SW_CONDITIONS_NOT_SATISFIED_2 0x85
-#define U2F_SW_NO_ERROR_1 0x90
-#define U2F_SW_NO_ERROR_2 0x00
+#define U2F_SW_INSTRUCTION_NOT_SUPPORTED_1 0x6D
+#define U2F_SW_INSTRUCTION_NOT_SUPPORTED_2 0x00
+#define U2F_SW_NO_ERROR_1 0x90
+#define U2F_SW_NO_ERROR_2 0x00
struct U2fNfc {
Nfc* nfc;
@@ -52,6 +52,12 @@ static bool u2f_nfc_transmit_apdu(
bit_buffer_reset(tx_buffer);
bit_buffer_append_bytes(tx_buffer, apdu, apdu_len);
+ FuriString* str = furi_string_alloc();
+ for(size_t i = 0; i < bit_buffer_get_size_bytes(tx_buffer); i++) {
+ furi_string_cat_printf(str, "%02X ", bit_buffer_get_byte(tx_buffer, i));
+ }
+ FURI_LOG_T(TAG, "TX: %s", furi_string_get_cstr(str));
+ furi_string_free(str);
Iso14443_4aError error = iso14443_4a_listener_send_block(iso14443_listener, tx_buffer);
if(error != Iso14443_4aErrorNone) {
@@ -131,8 +137,22 @@ NfcCommand u2f_nfc_worker_listener_callback(NfcGenericEvent event, void* context
const uint8_t* rx_data = bit_buffer_get_data(rx_buffer);
uint16_t rx_size = bit_buffer_get_size_bytes(rx_buffer);
- if(rx_size == 0) {
+ FuriString* str = furi_string_alloc();
+ for(size_t i = 0; i < rx_size; i++) {
+ furi_string_cat_printf(str, "%02X ", rx_data[i]);
+ }
+ FURI_LOG_T(TAG, "RX: %s", furi_string_get_cstr(str));
+ furi_string_free(str);
+
+ if(rx_size < 5) {
FURI_LOG_W(TAG, "No APDU in frame: %u", rx_size);
+ const uint8_t reject_sw[2] = {
+ U2F_SW_INSTRUCTION_NOT_SUPPORTED_1,
+ U2F_SW_INSTRUCTION_NOT_SUPPORTED_2,
+ };
+ if(!u2f_nfc_transmit_apdu(u2f_nfc, iso14443_listener, reject_sw, sizeof(reject_sw))) {
+ break;
+ }
break;
}
@@ -152,8 +172,8 @@ NfcCommand u2f_nfc_worker_listener_callback(NfcGenericEvent event, void* context
if(!u2f_nfc->applet_selected && ins != U2F_APDU_SELECT) {
const uint8_t reject_sw[2] = {
- U2F_SW_CONDITIONS_NOT_SATISFIED_1,
- U2F_SW_CONDITIONS_NOT_SATISFIED_2,
+ U2F_SW_INSTRUCTION_NOT_SUPPORTED_1,
+ U2F_SW_INSTRUCTION_NOT_SUPPORTED_2,
};
FURI_LOG_W(TAG, "Reject APDU before SELECT: ins=%02x", ins);
if(!u2f_nfc_transmit_apdu(u2f_nfc, iso14443_listener, reject_sw, sizeof(reject_sw))) {
i have to go, but if you have more ideas ill try them whenever i have time |
|
Ok, thanks for testing. I'll try to fix it tomorrow. |
|
Also I'll try to change ATS values in u2f.nfc. |
|
Just tested with an Android device (Google Pixel 6, fully updated on Android 16) with https://webauthn.io, and it just crashes the Flipper when trying to register. My phone does says that it was successful, but it is not able to authenticate afterwards. Flipper log: It is crashing in the NfcWorker, so not sure if that's truly an issue with this PR or something else. Here's the stack trace for both the U2F app and NfcWorker: |
|
That looks like it would've worked, but some bit buffer somewhere is too small so it failed copying the response |
|
@aaronjamt does it crash every time? I can't really reproduce it on Android 16 but I remember something simillar happend to me before |
Yeah, I tried it a few times (both the "Register" and "Authenticate" buttons on that website) and it crashed every time. |
|
@asaldele1 I also was testing with ios device |

What's new
Add U2F over NFC support to the U2F application.
For the reviewer