Skip to content

Commit

Permalink
hf 15 info: show all type matches and check ST25TVxC signature
Browse files Browse the repository at this point in the history
  • Loading branch information
doegox committed Dec 15, 2024
1 parent be79654 commit 59ae5d2
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...

## [unreleased][unreleased]
- Changed `hf 15 info` to show all type matches and check ST25TVxC signature (@doegox)
- Added initial support for ST25TN and its signature verification (@doegox)
- Changed originality checks handling to refactor code and pk data (@doegox)
- Changed `uniq.yaml` workflow to be case-insensitive (@iceman1001)
Expand Down
128 changes: 106 additions & 22 deletions client/src/cmdhf15.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,14 +331,15 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
// get a product description based on the UID
// uid[8] tag uid
// returns description of the best match
static const char *getTagInfo_15(const uint8_t *uid) {
static void printTagInfo_15(const uint8_t *uid) {
if (uid == NULL) {
return "";
return;
}

uint64_t myuid, mask;
int i = 0, best = -1;
memcpy(&myuid, uid, sizeof(uint64_t));
// find first best match
while (uidmapping[i].mask > 0) {
if (uidmapping[i].mask > 64) {
mask = uidmapping[i].mask;
Expand All @@ -356,10 +357,23 @@ static const char *getTagInfo_15(const uint8_t *uid) {
}
i++;
}
if (best >= 0) {
i = 0;
while (uidmapping[i].mask > 0) {
if (uidmapping[i].mask > 64) {
mask = uidmapping[i].mask;
} else {
mask = (~0ULL) << (64 - uidmapping[i].mask);
}
if (((myuid & mask) == uidmapping[i].uid) && (uidmapping[i].mask == uidmapping[best].mask)) {
PrintAndLogEx(SUCCESS, "TYPE MATCH " _YELLOW_("%s"), uidmapping[i].desc);
}
i++;
}
} else {
PrintAndLogEx(SUCCESS, "TYPE...... " _YELLOW_("%s"), uidmapping[i].desc);
}

if (best >= 0)
return uidmapping[best].desc;
return uidmapping[i].desc;
}

// return a clear-text message to an errorcode
Expand Down Expand Up @@ -446,7 +460,7 @@ static int getUID(bool verbose, bool loop, uint8_t *buf) {
if (verbose) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%s"), iso15693_sprintUID(NULL, buf));
PrintAndLogEx(SUCCESS, "TYPE... " _YELLOW_("%s"), getTagInfo_15(buf));
printTagInfo_15(buf);
PrintAndLogEx(NORMAL, "");
}
res = PM3_SUCCESS;
Expand Down Expand Up @@ -878,6 +892,66 @@ static int NxpSysInfo(uint8_t *uid) {
return PM3_SUCCESS;
}

static int StCheckSig(uint8_t *uid) {
// request to be sent to device/card
uint8_t approxlen = 2 + 8 + 1 + 2;
iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen);
if (packet == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}

// ISO15693 Protocol params
packet->raw[packet->rawlen++] = arg_get_raw_flag(HF15_UID_LENGTH, false, false, false);
packet->raw[packet->rawlen++] = ISO15693_READBLOCK;
// add UID (scan, uid)
memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH);
packet->rawlen += HF15_UID_LENGTH;
packet->flags = (ISO15_CONNECT| ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT);
uint16_t blkoff = packet->rawlen;
char signature_hex[65] = {0};
for (int j=0; j<17; j++) {
packet->rawlen = blkoff;
// block no
packet->raw[packet->rawlen++] = 0x3F + j;
// crc
AddCrc15(packet->raw, packet->rawlen);
packet->rawlen += 2;
clearCommandBuffer();
SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
PrintAndLogEx(DEBUG, "iso15693 timeout");
free(packet);
DropField();
return PM3_ETIMEOUT;
}
ISO15_ERROR_HANDLING_RESPONSE
uint8_t *d = resp.data.asBytes;
ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length)
if (j==0) {
if (memcmp(d + 1, "K04S", 4) != 0) {
// No signature
free(packet);
return PM3_ESOFT;
}
} else {
memcpy(signature_hex + ((j - 1) * 4), d + 1, 4);
}
packet->flags = (ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT);
}
free(packet);
DropField();
uint8_t signature[16];
size_t signature_len;
hexstr_to_byte_array(signature_hex, signature, &signature_len);
uint8_t uid_swap[HF15_UID_LENGTH];
reverse_array_copy(uid, HF15_UID_LENGTH, uid_swap);
int index = originality_check_verify_ex(uid_swap, HF15_UID_LENGTH, signature, signature_len, PK_ST25TV, false, true);
PrintAndLogEx(NORMAL, "");
return originality_check_print(signature, signature_len, index);
}

/**
* Commandline handling: HF15 CMD SYSINFO
* get system information from tag/VICC
Expand Down Expand Up @@ -986,7 +1060,7 @@ static int CmdHF15Info(const char *Cmd) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(SUCCESS, "UID....... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
PrintAndLogEx(SUCCESS, "TYPE...... " _YELLOW_("%s"), getTagInfo_15(d + 2));
printTagInfo_15(d + 2);
PrintAndLogEx(SUCCESS, "SYSINFO... %s", sprint_hex(d, resp.length - 2));

// DSFID
Expand Down Expand Up @@ -1024,19 +1098,29 @@ static int CmdHF15Info(const char *Cmd) {
uint8_t nxp_version = d[6] & 0x18;
PrintAndLogEx(DEBUG, "NXP Version: %02x", nxp_version);

if (d[8] == 0x04 && d[7] == 0x01 && nxp_version == 0x08) {
PrintAndLogEx(DEBUG, "SLIX2 Detected, getting NXP System Info");
return NxpSysInfo(uid);

} else if (d[8] == 0x04 && d[7] == 0x01 && nxp_version == 0x18) { // If it is an NTAG 5
PrintAndLogEx(DEBUG, "NTAG 5 Detected, getting NXP System Info");
return NxpSysInfo(uid);

} else if (d[8] == 0x04 && (d[7] == 0x01 || d[7] == 0x02 || d[7] == 0x03)) { // If SLI, SLIX, SLIX-l, or SLIX-S check EAS status
PrintAndLogEx(DEBUG, "SLI, SLIX, SLIX-L, or SLIX-S Detected checking EAS status");
return NxpTestEAS(uid);
if (d[8] == 0x04) {
// NXP
if (d[7] == 0x01 && nxp_version == 0x08) {
PrintAndLogEx(DEBUG, "SLIX2 Detected, getting NXP System Info");
return NxpSysInfo(uid);
} else if (d[7] == 0x01 && nxp_version == 0x18) { // If it is an NTAG 5
PrintAndLogEx(DEBUG, "NTAG 5 Detected, getting NXP System Info");
return NxpSysInfo(uid);
} else if ((d[7] == 0x01 || d[7] == 0x02 || d[7] == 0x03)) { // If SLI, SLIX, SLIX-l, or SLIX-S check EAS status
PrintAndLogEx(DEBUG, "SLI, SLIX, SLIX-L, or SLIX-S Detected checking EAS status");
return NxpTestEAS(uid);
}
} else if (d[8] == 0x02) {
// ST, check d[7]:
// ST25TV512C/ST25TV02KC 0x08
// ST25TV512/ST25TV02K 0x23
// ST25TV04K-P 0x35
// ST25TV16K/ST25TV64K 0x48
if (d[7] == 0x08) {
PrintAndLogEx(DEBUG, "ST25TVxC Detected, getting ST Signature");
return StCheckSig(uid);
}
}

PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
Expand Down Expand Up @@ -1320,7 +1404,7 @@ static void print_tag_15693(iso15_tag_t *tag, bool dense_output, bool verbose) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " --%.*s", (tag->bytesPerPage * 3), dashes);
PrintAndLogEx(SUCCESS, "UID....... " _GREEN_("%s"), iso15693_sprintUID(NULL, tag->uid));
PrintAndLogEx(SUCCESS, "TYPE...... " _YELLOW_("%s"), getTagInfo_15(tag->uid));
printTagInfo_15(tag->uid);
PrintAndLogEx(SUCCESS, "DSFID..... 0x%02X", tag->dsfid);
PrintAndLogEx(SUCCESS, "AFI....... 0x%02X", tag->afi);
PrintAndLogEx(SUCCESS, "IC ref.... 0x%02X", tag->ic);
Expand Down Expand Up @@ -1849,7 +1933,7 @@ static int CmdHF15Dump(const char *Cmd) {
tag->pagesCount = d[dCpt++] + 1;
tag->bytesPerPage = d[dCpt++] + 1;
} else {
// Set tag memory layout values (if can't be readed in SYSINFO)
// Set tag memory layout values (if can't be read in SYSINFO)
tag->bytesPerPage = blocksize;
tag->pagesCount = 128;
}
Expand All @@ -1858,7 +1942,7 @@ static int CmdHF15Dump(const char *Cmd) {
tag->ic = d[dCpt++];
}

// add lenght for blockno (1)
// add length for blockno (1)
packet->rawlen++;
packet->raw[0] |= ISO15_REQ_OPTION; // Add option to dump lock status
packet->raw[1] = ISO15693_READBLOCK;
Expand Down
4 changes: 2 additions & 2 deletions client/src/crypto/originality.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ const ecdsa_publickey_ng_t manufacturer_public_keys[] = {
// ref: AN5660 TruST25 digital signature for ST25TN512 and ST25TN01K devices
{PK_ST25TN, MBEDTLS_ECP_DP_SECP128R1, 33, "ST25TN TruST25 (ST) KeyID 05",
"0440004F974F7C76BC8718E523D85FA7B354A9A992BFA966CB8219242F9D274FD6"},
// FIXME: need to implement support for ST25TV signature check. hash=sha256 - from block 63, starting with KeyID ?
// ref: AN5104 TruST25 digital signature for ST25TV512 and ST25TV02K devices ?
// ref: AN5149 TruST25 digital signature for ST25DV02K-W1, ST25DV02K-W2 devices ?
// ref: AN5580 TruST25 digital signature for ST25TV512C and ST25TV02KC devices
{PK_ST25TV, MBEDTLS_ECP_DP_SECP128R1, 33, "ST25TV TruST25 (ST) key 04?",
{PK_ST25TV, MBEDTLS_ECP_DP_SECP128R1, 33, "ST25TV TruST25 (ST) KeyID 04",
"04101E188A8B4CDDBC62D5BC3E0E6850F0C2730E744B79765A0E079907FBDB01BC"},

{PK_15, MBEDTLS_ECP_DP_SECP128R1, 33, "NXP ICODE DNA, ICODE SLIX2",
Expand Down

0 comments on commit 59ae5d2

Please sign in to comment.