Open cfmdmedia opened 1 year ago
Strange, mine does not show in logs at all. And "nfc tools" android app, says it's "Mifare Plus".
Did you get this working?
Nope
But, I was able make PN532 respond to a command on UART with a PHP script 😄 , so eventually If I can trigger a known to work tag, I might be able to find out the sequence of commands to active my yubikey.
I give up for now, all my other tags (including some credit cards) respond, but not the yubikey.
However, a regular Mifare Classic card/tag could be turned into semi-secure one. In short: set a secure key for Key B for some or all sectors and set access bits to allow read and write only with Key B (C1C2C3 = 011). https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf
But that will turn the tag into NDEF non-compliant, and will require modifications in PN532 component to inject a custom key and I doubt it will be accepted into esphome.
I feel like I was able to read the yubikey nfc from the arduino PN532 example. I'll have to hook it backup and have a looksee.
I was able to read the Yubikey NFC OTP code with arduino
These three ADPU commands access the OTP code
uint8_t apdu1[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
uint8_t apdu2[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x04};
uint8_t apdu3[] = {0x00, 0xB0, 0x00, 0x00, 0x00};
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_PN532.h>
// If using the breakout with SPI, define the pins for SPI communication.
#define PN532_SCK (13)
#define PN532_MOSI (11)
#define PN532_SS (10)
#define PN532_MISO (12)
// If using the breakout or shield with I2C, define just the pins connected
// to the IRQ and reset lines. Use the values below (2, 3) for the shield!
#define PN532_IRQ (9)
#define PN532_RESET (8) // Not connected by default on the NFC Shield
// Uncomment just _one_ line below depending on how your breakout or shield
// is connected to the Arduino:
// Use this line for a breakout with a software SPI connection (recommended):
Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);
// Use this line for a breakout with a hardware SPI connection. Note that
// the PN532 SCK, MOSI, and MISO pins need to be connected to the Arduino's
// hardware SPI SCK, MOSI, and MISO pins. On an Arduino Uno these are
// SCK = 13, MOSI = 11, MISO = 12. The SS line can be any digital IO pin.
//Adafruit_PN532 nfc(PN532_SS);
// Or use this line for a breakout or shield with an I2C connection:
//Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);
void setup(void) {
Serial.begin(115200);
while (!Serial) delay(10); // for Leonardo/Micro/Zero
Serial.println("Hello!");
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (!versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
// Got ok data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);
// configure board to read RFID tags
nfc.SAMConfig();
Serial.println("Waiting for an ISO14443A Card ...");
}
void loop(void) {
uint8_t success;
uint8_t apdu1[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
uint8_t apdu2[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x04};
uint8_t apdu3[] = {0x00, 0xB0, 0x00, 0x00, 0x00};
uint8_t response[255];
uint8_t responseLength = sizeof(response);
success = nfc.inListPassiveTarget();
if (success) {
Serial.println("NFC tag detected");
// Send first APDU command
if (!nfc.inDataExchange(apdu1, sizeof(apdu1), response, &responseLength)) {
Serial.println("Error in first APDU command");
return;
} else {
Serial.print("Received (SW1=0x"); Serial.print(response[responseLength-2], HEX);
Serial.print(", SW2=0x"); Serial.print(response[responseLength-1], HEX); Serial.println(")");
}
// Send second APDU command
responseLength = sizeof(response);
if (!nfc.inDataExchange(apdu2, sizeof(apdu2), response, &responseLength)) {
Serial.println("Error in second APDU command");
return;
} else {
Serial.print("Received (SW1=0x"); Serial.print(response[responseLength-2], HEX);
Serial.print(", SW2=0x"); Serial.print(response[responseLength-1], HEX); Serial.println(")");
}
// Send third APDU command and read response
responseLength = sizeof(response);
if (nfc.inDataExchange(apdu3, sizeof(apdu3), response, &responseLength)) {
Serial.println("APDU command successful");
Serial.print("Response length: "); Serial.println(responseLength);
Serial.println("Response data:");
nfc.PrintHexChar(response, responseLength);
// Process the response to extract URL
if (responseLength > 3) { // We need at least 4 bytes for a valid NDEF message
// Assume the payload starts at the 7th byte and continues until the end minus 2 bytes (SW1 and SW2)
uint8_t payloadStart = 7;
uint8_t payloadEnd = responseLength - 2;
String url = "";
for (int i = payloadStart; i < payloadEnd; i++) {
if (response[i] >= 32 && response[i] <= 126) { // Only print printable ASCII characters
url += (char)response[i];
}
}
Serial.print("Decoded URL: ");
Serial.println(url);
// Extract the OTP code from the URL
int otpStart = url.lastIndexOf('/') + 1; // OTP code starts after the last '/'
String otpCode = url.substring(otpStart);
Serial.print("Extracted OTP Code: ");
Serial.println(otpCode);
} else {
Serial.println("Response too short for NDEF message");
}
} else {
Serial.println("Error in APDU command");
}
} else {
Serial.println("Waiting for an NFC card ...");
}
delay(1000);
}
Waiting for an NFC card ...
Tag number: 1
NFC tag detected
Received (SW1=0x90, SW2=0x0)
Received (SW1=0x90, SW2=0x0)
APDU command successful
Response length: 50
Response data:
00 2E D1 01 2A 55 04 68 6F 6D 65 2D 61 73 73 69 73 74 61 6E 74 2E 69 6F 2F 74 61 67 32 2F 30 30 30 30 37 36 37 31 32 32 31 36 33 33 32 30 33 30 90 00 ..�.*U.home-assistant.io/tag2/000076712216332030�.
Decoded URL: home-assistant.io/tag2/000076712216332030
Extracted OTP Code: 000076712216332030
Waiting for an NFC card ...
Not pretty but I was able to persevere through it with Jesse's help
spi:
clk_pin: GPIO04
miso_pin: GPIO05
mosi_pin: GPIO06
pn532_spi:
cs_pin: GPIO07
id: pn532_component
update_interval: never
text_sensor:
- platform: yubikey_otp
name: "Yubikey OTP"
id: yubikey_nfc_otp
pn532_id: pn532_component
update_interval: 5s
https://github.com/NonaSuomy/esphome/tree/yubikey_nfc_otp/esphome/components/yubikey_otp
[05:20:56][D][pn532:469]: APDU commands successful [05:20:56][D][pn532:470]: Response: 00.00.2E.D1.01.2A.55.04.68.6F.6D.65.2D.61.73.73.69.73.74.61.6E.74.2E.69.6F.2F.74.61.67.32.2F.30.30.30.30.37.36.37.31.32.32.31.36.34.39.33.32.38.37.90.00 (51) [05:20:56][D][pn532:484]: Decoded URL: home-assistant.io/tag2/000076712216493287 [05:20:56][D][pn532:488]: Extracted OTP Code: 000076712216493287 [05:20:56][D][yubikey_otp:024]: OTP Code: 000076712216493287 [05:20:56][V][text_sensor:013]: 'Yubikey OTP': Received new state 000076712216493287 [05:20:56][D][text_sensor:064]: 'Yubikey OTP': Sending state '000076712216493287'
@NonaSuomy first of all, thank you so much for this code example, it is exactly what i needed!
but i have one issue which i cannot solve... my Extracted OTP Code always becomes non-valid towards the end and i cannot figure out exactly why... (could be buffer sue maybe..?)
this is my respone in serial output
notice the T1@,Bh
Waiting for an NFC card ...
Tag number: 1
NFC tag detected
Received (SW1=0x90, SW2=0x0)
Received (SW1=0x90, SW2=0x0)
APDU command successful
Response length: 71
Response data:
00 43 D1 01 3F 55 04 6D 79 2E 79 75 62 69 63 6F 2E 63 6F 6D 2F 79 6B 2F 23 63 63 63 63 63 62 6E 74 69 6E 6B 64 66 67 76 6E 67 66 62 74 75 6E 6E 62 6E 72 67 6E 63 67 6E 54 31 81 40 01 00 00 00 2C 09 0C 42 68 BB 0D .C�.?U.my.yubico.com/yk/#cccccbntinkdfgvngfbtunnbnrgncgnT1�@....,..Bh�.
Decoded URL: my.yubico.com/yk/#cccccbntinkdfgvngfbtunnbnrgncgnT1@,Bh
Extracted OTP Code: #cccccbntinkdfgvngfbtunnbnrgncgnT1@,Bh
Waiting for an NFC card ...
would you know how to solve this issue, it would help me out big-time 😄
EDIT:
sometimes i also see the following error:
[1110148][E][Wire.cpp:522] requestFrom(): i2cRead returned Error -1
EDIT 2: compared the length of a valid otp token and the corrupted one valid: 44 invalid; 35
Are you using I2C or SPI?
I was having the same issue when using I2C.
If you are using SPI (Allows a larger buffer) if not switch to it. If you are using SPI with that problem, you maybe can try playing with this number: https://github.com/adafruit/Adafruit-PN532/blob/f4e1a91afd0163d8601b243ddcbb2a580da6552a/Adafruit_PN532.cpp#L78
It's a limitation with the adafruit library.
i was doing it with i2c, tried with spi, same issue!
the fix was changing the PN532_PACKBUFFSIZ to a higher number
i then changed back to i2c and it now works perfectly! thank you so much!!!
just a shame that there is no good way to override the PN532_PACKBUFFSIZ definition without maybe "forking" it :/
You're welcome!
May have just been an issue with the esphome implementation of i2c that I was thinking about.
SPI though has better stability overall and can fully control the pn523 IC. I would personally stick with it. It's only 1 extra pin.
Someone said that it used to be set to 261 or something then someone got confused about packet buffer header size and changed it to 64 then it just got left there.
Another person said if you require even more than 255 of buffer that you have to make your own apdu protocol to chunk data properly.
Describe the problem you have/What new integration you would like I have a PN532 component and connected it with IIC to an ESP32 and used the PN532 esphome component. It can read the data written to NFC tags with the Homeassistant App but is not able to read the data from a Yubikey 5 NFC.
YAML code:
Debug logs when scanning a NFC tag with data written to it via the Homeassistant App:
Debug logs when scanning the Yubikey 5 NFC:
With the NFC reader of my Smartphone the Yubikey OTP is readable. So the feature is active on the Yubikey.
It would be really nice if the PN532 component of ESPhome would also support reading the NDEF data of other NFC tags like the data from a Yubikey 5 NFC.
Please describe your use case for this integration and alternatives you've tried: I want to read the OTP of the Yubikey with a custom NFC reader to use it a door key. Since the OTP always changes it is more secure than using a static NFC tag that can be cloned easily.
Additional context I found this code where someone already build something similar but it is written in Arduino ADA language and I did not managed to translate this into a custom component. Some info about the yubikey ndef interface