Yubico / yubikey-manager

Python library and command line tool for configuring any YubiKey over all USB interfaces.
https://developers.yubico.com/yubikey-manager/
BSD 2-Clause "Simplified" License
862 stars 125 forks source link

ykman otp ndef 1 how do you read or generate a response that is in this slot? #564

Closed NonaSuomy closed 10 months ago

NonaSuomy commented 1 year ago

How do you read a slot with ndef programmed from ykman cli? So ykman cli would spit out something like this: https://my.yubico.com/neo/XXXXXXXXXX

Thank you.

dainnilsson commented 1 year ago

There's no command in ykman to do so. It's unclear if you want to do this over USB or NFC. For USB it isn't possible. For NFC you'd read it like a standard NFC NDEF tag.

NonaSuomy commented 1 year ago

I didn't know ykman cli worked with nfc thought it was just USB so yes was for USB thank you for your answer.

Any chance you know of any arduino code with the pn532 i2c module? I've tried to read this nfc ndef data with the adafruit library but it doesn't seem possible.

dainnilsson commented 1 year ago

No, I have no familiarity with Arduino I'm afraid.

NonaSuomy commented 2 months ago

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 <Adafruit_PN532.h>
#include <SPI.h>

#define PN532_SS    (10)
#define PN532_RESET (9)

Adafruit_PN532 nfc(PN532_SS, PN532_RESET);

void setup(void) {
  Serial.begin(115200);
  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 ...
NonaSuomy commented 2 months ago

Once you have this OTP code 000076712216332030 how do I verify it on another system etc?