mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-17 18:50:32 +08:00
Merge branch 'master' into experimental_varlen
* master: (27 commits) textual style redundant assignment timeout fix small fix add termcap add readline and small fix rdp textual null term? fix: https://github.com/RfidResearchGroup/proxmark3/issues/166 add dlls to release style style test fix test fixes another fix fix memleak fix textual use printandlogex ...
This commit is contained in:
commit
7cbcf8163c
20 changed files with 519 additions and 534 deletions
|
@ -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]
|
||||
- Fix/Add 'hf mf sim' bugs fix, RATS support, etc (@mceloff)
|
||||
- Fix serial of FPC. (@ryan)
|
||||
- Fix 'data shiftgraphzero' corrupting end of GraphBuffer (@doegox)
|
||||
- Fix 'hf legic info' - unsegmented card now uses card size to calc remaining length (@iceman)
|
||||
|
|
|
@ -2,6 +2,7 @@ Proxmark3 RDV4.0 Dedicated Github
|
|||
===============
|
||||
This repo is based on iceman fork for proxmark3. It is dedicated to bringing the most out of the new features for proxmark3 RDV4.0 new hardware and design.
|
||||
|
||||
[](https://ci.appveyor.com/project/iceman1001/proxmark3-ji4wj/branch/master)
|
||||
[](https://github.com/RfidResearchGroup/proxmark3/releases/latest)
|
||||
|
||||
<a href="http://www.youtube.com/watch?feature=player_embedded&v=uyJ-y0kSWfc
|
||||
|
|
22
appveyor.yml
22
appveyor.yml
|
@ -160,6 +160,24 @@ build_script:
|
|||
Copy-Item C:\ProxSpace\pm3\client\hardnested\*.bin C:\ProxSpace\Release\hardnested
|
||||
|
||||
Copy-Item C:\ProxSpace\pm3\client\hardnested\tables\*.bin.z C:\ProxSpace\Release\hardnested\tables
|
||||
|
||||
# dll files
|
||||
|
||||
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libgcc_s_dw2-1.dll C:\ProxSpace\Release
|
||||
|
||||
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libstdc++-6.dll C:\ProxSpace\Release
|
||||
|
||||
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libwinpthread-1.dll C:\ProxSpace\Release
|
||||
|
||||
Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Core.dll C:\ProxSpace\Release
|
||||
|
||||
Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Gui.dll C:\ProxSpace\Release
|
||||
|
||||
Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Widgets.dll C:\ProxSpace\Release
|
||||
|
||||
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libreadline*.dll C:\ProxSpace\Release
|
||||
|
||||
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libtermcap-0.dll C:\ProxSpace\Release
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
|
@ -256,8 +274,8 @@ test_script:
|
|||
#--- end Job
|
||||
|
||||
[bool]$res=$false
|
||||
# Wait 120 sec timeout for Job
|
||||
if(Wait-Job $Job -Timeout 150){
|
||||
# Wait 180 sec timeout for Job
|
||||
if(Wait-Job $Job -Timeout 180){
|
||||
$Results = $Job | Receive-Job
|
||||
if($Results -like "true"){
|
||||
$res=$true
|
||||
|
|
|
@ -451,23 +451,23 @@ void FpgaWriteConfWord(uint8_t v) {
|
|||
void SetAdcMuxFor(uint32_t whichGpio) {
|
||||
|
||||
#ifndef WITH_FPC
|
||||
// When compiled without FPC support
|
||||
AT91C_BASE_PIOA->PIO_OER =
|
||||
GPIO_MUXSEL_HIPKD |
|
||||
GPIO_MUXSEL_LOPKD |
|
||||
GPIO_MUXSEL_LORAW |
|
||||
GPIO_MUXSEL_HIRAW;
|
||||
// When compiled without FPC support
|
||||
AT91C_BASE_PIOA->PIO_OER =
|
||||
GPIO_MUXSEL_HIPKD |
|
||||
GPIO_MUXSEL_LOPKD |
|
||||
GPIO_MUXSEL_LORAW |
|
||||
GPIO_MUXSEL_HIRAW;
|
||||
|
||||
AT91C_BASE_PIOA->PIO_PER =
|
||||
GPIO_MUXSEL_HIPKD |
|
||||
GPIO_MUXSEL_LOPKD |
|
||||
GPIO_MUXSEL_LORAW |
|
||||
GPIO_MUXSEL_HIRAW;
|
||||
AT91C_BASE_PIOA->PIO_PER =
|
||||
GPIO_MUXSEL_HIPKD |
|
||||
GPIO_MUXSEL_LOPKD |
|
||||
GPIO_MUXSEL_LORAW |
|
||||
GPIO_MUXSEL_HIRAW;
|
||||
|
||||
LOW(GPIO_MUXSEL_HIPKD);
|
||||
LOW(GPIO_MUXSEL_LOPKD);
|
||||
LOW(GPIO_MUXSEL_HIRAW);
|
||||
LOW(GPIO_MUXSEL_LORAW);
|
||||
LOW(GPIO_MUXSEL_HIPKD);
|
||||
LOW(GPIO_MUXSEL_LOPKD);
|
||||
LOW(GPIO_MUXSEL_HIRAW);
|
||||
LOW(GPIO_MUXSEL_LORAW);
|
||||
|
||||
#else
|
||||
// FPC serial uses HIRAW/LOWRAW pins, so they are excluded here.
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
#include "protocols.h"
|
||||
#include "apps.h"
|
||||
|
||||
uint8_t MifareCardType;
|
||||
|
||||
static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
||||
uint8_t sector_trailer[16];
|
||||
emlGetMem(sector_trailer, blockNo, 1);
|
||||
|
@ -151,196 +149,188 @@ static bool IsAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool MifareSimInit(uint16_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len) {
|
||||
static bool MifareSimInit(uint16_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) {
|
||||
|
||||
// SPEC: https://www.nxp.com/docs/en/application-note/AN10833.pdf
|
||||
// ATQA
|
||||
static uint8_t rATQA_Mini[] = {0x04, 0x00}; // indicate Mifare classic Mini 4Byte UID
|
||||
static uint8_t rATQA_1k[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID
|
||||
static uint8_t rATQA_2k[] = {0x04, 0x00}; // indicate Mifare classic 2k 4Byte UID
|
||||
static uint8_t rATQA_4k[] = {0x02, 0x00}; // indicate Mifare classic 4k 4Byte UID
|
||||
|
||||
static uint8_t rATQA_Mini_4B[] = {0x44, 0x00}; // indicate Mifare classic Mini 4Byte UID
|
||||
static uint8_t rATQA_Mini_7B[] = {0x44, 0x00}; // indicate Mifare classic Mini 7Byte UID
|
||||
static uint8_t rATQA_Mini_10B[] = {0x44, 0x00}; // indicate Mifare classic Mini 10Byte UID
|
||||
|
||||
static uint8_t rATQA_1k_4B[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID
|
||||
static uint8_t rATQA_1k_7B[] = {0x44, 0x00}; // indicate Mifare classic 1k 7Byte UID
|
||||
static uint8_t rATQA_1k_10B[] = {0x42, 0x00}; // indicate Mifare classic 4k 10Byte UID
|
||||
|
||||
static uint8_t rATQA_2k_4B[] = {0x04, 0x00}; // indicate Mifare classic 2k 4Byte UID
|
||||
static uint8_t rATQA_2k_7B[] = {0x44, 0x00}; // indicate Mifare classic 2k 7Byte UID
|
||||
static uint8_t rATQA_2k_10B[] = {0x42, 0x00}; // indicate Mifare classic 4k 10Byte UID
|
||||
|
||||
static uint8_t rATQA_4k_4B[] = {0x02, 0x00}; // indicate Mifare classic 4k 4Byte UID
|
||||
static uint8_t rATQA_4k_7B[] = {0x42, 0x00}; // indicate Mifare classic 4k 7Byte UID
|
||||
static uint8_t rATQA_4k_10B[] = {0x42, 0x00}; // indicate Mifare classic 4k 10Byte UID
|
||||
|
||||
static uint8_t rATQA[] = {0x00, 0x00};
|
||||
|
||||
// SAK + CRC
|
||||
static uint8_t rSAK_mini[] = {0x09, 0x3f, 0xcc}; // mifare Mini
|
||||
static uint8_t rSAK_1[] = {0x08, 0xb6, 0xdd}; // mifare 1k
|
||||
static uint8_t rSAK_2[] = {0x08, 0xb6, 0xdd}; // mifare 2k
|
||||
static uint8_t rSAK_4[] = {0x18, 0x37, 0xcd}; // mifare 4k
|
||||
// SAK
|
||||
static uint8_t rSAK_Mini = 0x09; // mifare Mini
|
||||
static uint8_t rSAK_1k = 0x08; // mifare 1k
|
||||
static uint8_t rSAK_2k = 0x08; // mifare 2k with RATS support
|
||||
static uint8_t rSAK_4k = 0x18; // mifare 4k
|
||||
|
||||
static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level
|
||||
static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level
|
||||
static uint8_t rUIDBCC3[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 3nd cascade level
|
||||
|
||||
static uint8_t rSAK1[] = {0x04, 0xda, 0x17}; // Acknowledge but indicate UID is not finished. Used for any MIFARE Classic CL1 with double UID size
|
||||
static uint8_t rATQA[] = {0x00, 0x00}; // Current ATQA
|
||||
static uint8_t rSAK[] = {0x00, 0x00, 0x00}; // Current SAK, CRC
|
||||
static uint8_t rSAKuid[] = {0x04, 0xda, 0x17}; // UID incomplete cascade bit, CRC
|
||||
|
||||
// RATS answer for 2K NXP mifare classic (with CRC)
|
||||
static uint8_t rRATS[] = {0x0c, 0x75, 0x77, 0x80, 0x02, 0xc1, 0x05, 0x2f, 0x2f, 0x01, 0xbc, 0xd6, 0x60, 0xd3};
|
||||
|
||||
*uid_len = 0;
|
||||
|
||||
// By default use 1K tag
|
||||
memcpy(rATQA, rATQA_1k, sizeof(rATQA));
|
||||
rSAK[0] = rSAK_1k;
|
||||
|
||||
//by default RATS not supported
|
||||
*rats_len = 0;
|
||||
*rats = NULL;
|
||||
|
||||
// -- Determine the UID
|
||||
// Can be set from emulator memory or incoming data
|
||||
// Length: 4,7,or 10 bytes
|
||||
|
||||
// Get UID, SAK, ATQA from EMUL
|
||||
if ((flags & FLAG_UID_IN_EMUL) == FLAG_UID_IN_EMUL) {
|
||||
emlGetMemBt(datain, 0, 10); // load 10bytes from EMUL to the datain pointer. to be used below.
|
||||
uint8_t block0[16];
|
||||
emlGetMemBt(block0, 0, 16);
|
||||
|
||||
// If uid size defined, copy only uid from EMUL to use, backward compatibility for 'hf_colin.c', 'hf_mattyrun.c'
|
||||
if ((flags & (FLAG_4B_UID_IN_DATA | FLAG_7B_UID_IN_DATA | FLAG_10B_UID_IN_DATA)) != 0) {
|
||||
memcpy(datain, block0, 10); // load 10bytes from EMUL to the datain pointer. to be used below.
|
||||
} else {
|
||||
// Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA
|
||||
if ((block0[0] ^ block0[1] ^ block0[2] ^ block0[3]) == block0[4] && (block0[6] & 0xc0) == 0) {
|
||||
flags |= FLAG_4B_UID_IN_DATA;
|
||||
memcpy(datain, block0, 4);
|
||||
rSAK[0] = block0[5];
|
||||
memcpy(rATQA, &block0[6], sizeof(rATQA));
|
||||
}
|
||||
// Check for 7 bytes UID: double size uid bits in ATQA
|
||||
else if ((block0[8] & 0xc0) == 0x40) {
|
||||
flags |= FLAG_7B_UID_IN_DATA;
|
||||
memcpy(datain, block0, 7);
|
||||
rSAK[0] = block0[7];
|
||||
memcpy(rATQA, &block0[8], sizeof(rATQA));
|
||||
} else {
|
||||
Dbprintf("[-] ERROR: Invalid dump. UID/SAK/ATQA not found");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Tune tag type, if defined directly
|
||||
// Otherwise use defined by default or extracted from EMUL
|
||||
if ((flags & FLAG_MF_MINI) == FLAG_MF_MINI) {
|
||||
memcpy(rATQA, rATQA_Mini, sizeof(rATQA));
|
||||
rSAK[0] = rSAK_Mini;
|
||||
Dbprintf("Mifare Mini");
|
||||
} else if ((flags & FLAG_MF_1K) == FLAG_MF_1K) {
|
||||
memcpy(rATQA, rATQA_1k, sizeof(rATQA));
|
||||
rSAK[0] = rSAK_1k;
|
||||
Dbprintf("Mifare 1K");
|
||||
} else if ((flags & FLAG_MF_2K) == FLAG_MF_2K) {
|
||||
memcpy(rATQA, rATQA_2k, sizeof(rATQA));
|
||||
rSAK[0] = rSAK_2k;
|
||||
*rats = rRATS;
|
||||
*rats_len = sizeof(rRATS);
|
||||
Dbprintf("Mifare 2K with RATS support");
|
||||
} else if ((flags & FLAG_MF_4K) == FLAG_MF_4K) {
|
||||
memcpy(rATQA, rATQA_4k, sizeof(rATQA));
|
||||
rSAK[0] = rSAK_4k;
|
||||
Dbprintf("Mifare 4K");
|
||||
}
|
||||
|
||||
// Prepare UID arrays
|
||||
if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) { // get UID from datain
|
||||
memcpy(rUIDBCC1, datain, 4);
|
||||
*uid_len = 4;
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("MifareSimInit - FLAG_4B_UID_IN_DATA => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_4B_UID_IN_DATA, flags, rUIDBCC1);
|
||||
|
||||
|
||||
// save CUID
|
||||
*cuid = bytes_to_num(rUIDBCC1, 4);
|
||||
// BCC
|
||||
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
|
||||
if (MF_DBGLEVEL >= MF_DBG_NONE) {
|
||||
Dbprintf("4B UID: %02x%02x%02x%02x", rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]);
|
||||
}
|
||||
|
||||
// Correct uid size bits in ATQA
|
||||
rATQA[0] = (rATQA[0] & 0x3f) | 0x00; // single size uid
|
||||
|
||||
} else if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) {
|
||||
memcpy(&rUIDBCC1[1], datain, 3);
|
||||
memcpy(rUIDBCC2, datain + 3, 4);
|
||||
*uid_len = 7;
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("MifareSimInit - FLAG_7B_UID_IN_DATA => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_7B_UID_IN_DATA, flags, rUIDBCC1);
|
||||
|
||||
// save CUID
|
||||
*cuid = bytes_to_num(rUIDBCC2, 4);
|
||||
// CascadeTag, CT
|
||||
rUIDBCC1[0] = MIFARE_SELECT_CT;
|
||||
// BCC
|
||||
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
|
||||
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
|
||||
if (MF_DBGLEVEL >= MF_DBG_NONE) {
|
||||
Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x",
|
||||
rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3]);
|
||||
}
|
||||
|
||||
// Correct uid size bits in ATQA
|
||||
rATQA[0] = (rATQA[0] & 0x3f) | 0x40; // double size uid
|
||||
|
||||
} else if ((flags & FLAG_10B_UID_IN_DATA) == FLAG_10B_UID_IN_DATA) {
|
||||
memcpy(&rUIDBCC1[1], datain, 3);
|
||||
memcpy(&rUIDBCC2[1], datain + 3, 3);
|
||||
memcpy(rUIDBCC3, datain + 6, 4);
|
||||
*uid_len = 10;
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("MifareSimInit - FLAG_10B_UID_IN_DATA => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_10B_UID_IN_DATA, flags, rUIDBCC1);
|
||||
|
||||
// save CUID
|
||||
*cuid = bytes_to_num(rUIDBCC3, 4);
|
||||
// CascadeTag, CT
|
||||
rUIDBCC1[0] = MIFARE_SELECT_CT;
|
||||
rUIDBCC2[0] = MIFARE_SELECT_CT;
|
||||
// BCC
|
||||
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
|
||||
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
|
||||
rUIDBCC3[4] = rUIDBCC3[0] ^ rUIDBCC3[1] ^ rUIDBCC3[2] ^ rUIDBCC3[3];
|
||||
|
||||
if (MF_DBGLEVEL >= MF_DBG_NONE) {
|
||||
Dbprintf("10B UID: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3],
|
||||
rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3],
|
||||
rUIDBCC3[0], rUIDBCC3[1], rUIDBCC3[2], rUIDBCC3[3]
|
||||
);
|
||||
}
|
||||
|
||||
// Correct uid size bits in ATQA
|
||||
rATQA[0] = (rATQA[0] & 0x3f) | 0x80; // triple size uid
|
||||
} else {
|
||||
Dbprintf("[-] ERROR: UID size not defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (*uid_len) {
|
||||
// Calculate actual CRC
|
||||
AddCrc14A(rSAK, sizeof(rSAK) - 2);
|
||||
|
||||
// UID 4B
|
||||
case 4:
|
||||
switch (MifareCardType) {
|
||||
case 0: // Mifare Mini
|
||||
memcpy(rATQA, rATQA_Mini_4B, sizeof rATQA_Mini_4B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_Mini_4B");
|
||||
break;
|
||||
case 1: // Mifare 1K
|
||||
memcpy(rATQA, rATQA_1k_4B, sizeof rATQA_1k_4B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_1k_4B");
|
||||
break;
|
||||
case 2: // Mifare 2K
|
||||
memcpy(rATQA, rATQA_2k_4B, sizeof rATQA_2k_4B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_2k_4B");
|
||||
break;
|
||||
case 4: // Mifare 4K
|
||||
memcpy(rATQA, rATQA_4k_4B, sizeof rATQA_4k_4B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_4k_4B");
|
||||
break;
|
||||
}
|
||||
|
||||
// save CUID
|
||||
*cuid = bytes_to_num(rUIDBCC1, 4);
|
||||
// BCC
|
||||
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
|
||||
if (MF_DBGLEVEL >= MF_DBG_NONE) {
|
||||
Dbprintf("4B UID: %02x%02x%02x%02x", rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]);
|
||||
}
|
||||
break;
|
||||
|
||||
// UID 7B
|
||||
case 7:
|
||||
|
||||
switch (MifareCardType) {
|
||||
case 0: // Mifare Mini
|
||||
memcpy(rATQA, rATQA_Mini_7B, sizeof rATQA_Mini_7B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_Mini_7B");
|
||||
break;
|
||||
case 1: // Mifare 1K
|
||||
memcpy(rATQA, rATQA_1k_7B, sizeof rATQA_1k_7B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_1k_7B");
|
||||
break;
|
||||
case 2: // Mifare 2K
|
||||
memcpy(rATQA, rATQA_2k_7B, sizeof rATQA_2k_7B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_2k_7B");
|
||||
break;
|
||||
case 4: // Mifare 4K
|
||||
memcpy(rATQA, rATQA_4k_7B, sizeof rATQA_4k_7B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_4k_4B");
|
||||
break;
|
||||
}
|
||||
|
||||
// save CUID
|
||||
*cuid = bytes_to_num(rUIDBCC2, 4);
|
||||
// CascadeTag, CT
|
||||
rUIDBCC1[0] = MIFARE_SELECT_CT;
|
||||
// BCC
|
||||
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
|
||||
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
|
||||
if (MF_DBGLEVEL >= MF_DBG_NONE) {
|
||||
Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x",
|
||||
rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3]);
|
||||
}
|
||||
break;
|
||||
|
||||
// UID 10B
|
||||
case 10:
|
||||
switch (MifareCardType) {
|
||||
case 0: // Mifare Mini
|
||||
memcpy(rATQA, rATQA_Mini_10B, sizeof rATQA_Mini_10B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_Mini_10B");
|
||||
break;
|
||||
case 1: // Mifare 1K
|
||||
memcpy(rATQA, rATQA_1k_10B, sizeof rATQA_1k_10B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_1k_10B");
|
||||
break;
|
||||
case 2: // Mifare 2K
|
||||
memcpy(rATQA, rATQA_2k_10B, sizeof rATQA_2k_10B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_2k_10B");
|
||||
break;
|
||||
case 4: // Mifare 4K
|
||||
memcpy(rATQA, rATQA_4k_10B, sizeof rATQA_4k_10B);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("=> Using rATQA_4k_10B");
|
||||
break;
|
||||
}
|
||||
|
||||
// save CUID
|
||||
*cuid = bytes_to_num(rUIDBCC3, 4);
|
||||
// CascadeTag, CT
|
||||
rUIDBCC1[0] = MIFARE_SELECT_CT;
|
||||
rUIDBCC2[0] = MIFARE_SELECT_CT;
|
||||
// BCC
|
||||
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
|
||||
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
|
||||
rUIDBCC3[4] = rUIDBCC3[0] ^ rUIDBCC3[1] ^ rUIDBCC3[2] ^ rUIDBCC3[3];
|
||||
|
||||
if (MF_DBGLEVEL >= MF_DBG_NONE) {
|
||||
Dbprintf("10B UID: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3],
|
||||
rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3],
|
||||
rUIDBCC3[0], rUIDBCC3[1], rUIDBCC3[2], rUIDBCC3[3]
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#define TAG_RESPONSE_COUNT 9
|
||||
#define TAG_RESPONSE_COUNT 6
|
||||
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = {
|
||||
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
|
||||
{ .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid
|
||||
{ .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid
|
||||
{ .response = rUIDBCC3, .response_n = sizeof(rUIDBCC3) }, // Anticollision cascade3 - respond with 3th part of uid
|
||||
{ .response = rSAK_mini, .response_n = sizeof(rSAK_mini) }, // SAK Mifare Mini
|
||||
{ .response = rSAK_1, .response_n = sizeof(rSAK_1) }, // SAK Mifare 1K
|
||||
{ .response = rSAK_2, .response_n = sizeof(rSAK_2) }, // SAK Mifare 2K
|
||||
{ .response = rSAK_4, .response_n = sizeof(rSAK_4) }, // SAK Mifare 4K
|
||||
{ .response = rSAK1, .response_n = sizeof(rSAK1) } // Acknowledge select - Need another cascades
|
||||
{ .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid
|
||||
{ .response = rUIDBCC3, .response_n = sizeof(rUIDBCC3) }, // Anticollision cascade3 - respond with 3th part of uid
|
||||
{ .response = rSAK, .response_n = sizeof(rSAK) }, //
|
||||
{ .response = rSAKuid, .response_n = sizeof(rSAKuid) } //
|
||||
};
|
||||
|
||||
// Prepare ("precompile") the responses of the anticollision phase.
|
||||
// There will be not enough time to do this at the moment the reader sends its REQA or SELECT
|
||||
// There are 9 predefined responses with a total of 32 bytes data to transmit.
|
||||
// There are 6 predefined responses with a total of 23 bytes data to transmit.
|
||||
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
|
||||
// 32 * 8 data bits, 32 * 1 parity bits, 9 start bits, 9 stop bits, 9 correction bits -> need 315 bytes buffer
|
||||
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 512
|
||||
// 23 * 8 data bits, 23 * 1 parity bits, 6 start bits, 6 stop bits, 6 correction bits -> need 225 bytes buffer
|
||||
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 225
|
||||
|
||||
uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
|
||||
// modulation buffer pointer and current buffer free space size
|
||||
|
@ -361,11 +351,8 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, tag_response_info_t *
|
|||
#define UIDBCC1 1
|
||||
#define UIDBCC2 2
|
||||
#define UIDBCC3 3
|
||||
#define SAK_MINI 4
|
||||
#define SAK_1 5
|
||||
#define SAK_2 6
|
||||
#define SAK_4 7
|
||||
#define SAK1 8
|
||||
#define SAK 4
|
||||
#define SAKuid 5
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -422,6 +409,9 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t
|
|||
uint8_t response[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||
uint8_t response_par[MAX_MIFARE_PARITY_SIZE] = {0x00};
|
||||
|
||||
uint8_t *rats = NULL;
|
||||
uint8_t rats_len = 0;
|
||||
|
||||
uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
//Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2
|
||||
|
@ -447,27 +437,10 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t
|
|||
|
||||
tUart *uart = GetUart();
|
||||
|
||||
if ((flags & FLAG_MF_MINI) == FLAG_MF_MINI) {
|
||||
MifareCardType = 0;
|
||||
Dbprintf("Mifare Mini");
|
||||
}
|
||||
if ((flags & FLAG_MF_1K) == FLAG_MF_1K) {
|
||||
MifareCardType = 1;
|
||||
Dbprintf("Mifare 1K");
|
||||
}
|
||||
if ((flags & FLAG_MF_2K) == FLAG_MF_2K) {
|
||||
MifareCardType = 2;
|
||||
Dbprintf("Mifare 2K");
|
||||
}
|
||||
if ((flags & FLAG_MF_4K) == FLAG_MF_4K) {
|
||||
MifareCardType = 4;
|
||||
Dbprintf("Mifare 4K");
|
||||
}
|
||||
|
||||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
if (MifareSimInit(flags, datain, &responses, &cuid, &uid_len) == false) {
|
||||
if (MifareSimInit(flags, datain, &responses, &cuid, &uid_len, &rats, &rats_len) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
return;
|
||||
}
|
||||
|
@ -579,34 +552,21 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t
|
|||
// Send SAK according UID len
|
||||
switch (uid_len) {
|
||||
case 4:
|
||||
switch (MifareCardType) {
|
||||
case 0: // Mifare Mini
|
||||
EmSendPrecompiledCmd(&responses[SAK_MINI]);
|
||||
break;
|
||||
case 1: // Mifare 1K
|
||||
EmSendPrecompiledCmd(&responses[SAK_1]);
|
||||
break;
|
||||
case 2: // Mifare 2K
|
||||
EmSendPrecompiledCmd(&responses[SAK_2]);
|
||||
break;
|
||||
case 4: // Mifare 4K
|
||||
EmSendPrecompiledCmd(&responses[SAK_4]);
|
||||
break;
|
||||
}
|
||||
|
||||
// UID completed
|
||||
EmSendPrecompiledCmd(&responses[SAK]);
|
||||
LED_B_ON();
|
||||
cardSTATE = MFEMUL_WORK;
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT1] cardSTATE = MFEMUL_WORK");
|
||||
break;
|
||||
case 7:
|
||||
// SAK => Need another select round
|
||||
EmSendPrecompiledCmd(&responses[SAK1]);
|
||||
EmSendPrecompiledCmd(&responses[SAKuid]);
|
||||
cardSTATE = MFEMUL_SELECT2;
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT1] cardSTATE = MFEMUL_SELECT2");
|
||||
break;
|
||||
case 10:
|
||||
// SAK => Need another select round
|
||||
EmSendPrecompiledCmd(&responses[SAK1]);
|
||||
EmSendPrecompiledCmd(&responses[SAKuid]);
|
||||
cardSTATE = MFEMUL_SELECT2;
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT1] cardSTATE = MFEMUL_SELECT2");
|
||||
break;
|
||||
|
@ -657,27 +617,14 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t
|
|||
switch (uid_len) {
|
||||
case 7:
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT2] SELECT CL2 %02x%02x%02x%02x received", receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5]);
|
||||
|
||||
switch (MifareCardType) {
|
||||
case 0: // Mifare Mini
|
||||
EmSendPrecompiledCmd(&responses[SAK_MINI]);
|
||||
break;
|
||||
case 1: // Mifare 1K
|
||||
EmSendPrecompiledCmd(&responses[SAK_1]);
|
||||
break;
|
||||
case 2: // Mifare 2K
|
||||
EmSendPrecompiledCmd(&responses[SAK_2]);
|
||||
break;
|
||||
case 4: // Mifare 4K
|
||||
EmSendPrecompiledCmd(&responses[SAK_4]);
|
||||
break;
|
||||
}
|
||||
// UID completed
|
||||
EmSendPrecompiledCmd(&responses[SAK]);
|
||||
cardSTATE = MFEMUL_WORK;
|
||||
LED_B_ON();
|
||||
break;
|
||||
case 10:
|
||||
// SAK => Need another select round
|
||||
EmSendPrecompiledCmd(&responses[SAK1]);
|
||||
EmSendPrecompiledCmd(&responses[SAKuid]);
|
||||
cardSTATE = MFEMUL_SELECT3;
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT2] cardSTATE = MFEMUL_SELECT3");
|
||||
default:
|
||||
|
@ -714,22 +661,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t
|
|||
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 &&
|
||||
receivedCmd[1] == 0x70 &&
|
||||
memcmp(&receivedCmd[2], responses[UIDBCC3].response, 4) == 0)) {
|
||||
|
||||
switch (MifareCardType) {
|
||||
case 0: // Mifare Mini
|
||||
EmSendPrecompiledCmd(&responses[SAK_MINI]);
|
||||
break;
|
||||
case 1: // Mifare 1K
|
||||
EmSendPrecompiledCmd(&responses[SAK_1]);
|
||||
break;
|
||||
case 2: // Mifare 2K
|
||||
EmSendPrecompiledCmd(&responses[SAK_2]);
|
||||
break;
|
||||
case 4: // Mifare 4K
|
||||
EmSendPrecompiledCmd(&responses[SAK_4]);
|
||||
break;
|
||||
}
|
||||
|
||||
// UID completed
|
||||
EmSendPrecompiledCmd(&responses[SAK]);
|
||||
cardSTATE = MFEMUL_WORK;
|
||||
LED_B_ON();
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
|
||||
|
@ -1003,9 +936,37 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t
|
|||
}
|
||||
|
||||
// case MFEMUL_WORK => CMD RATS
|
||||
if (receivedCmd_dec[0] == ISO14443A_CMD_RATS) {
|
||||
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV RATS => NACK");
|
||||
if (receivedCmd_len == 4 && receivedCmd_dec[0] == ISO14443A_CMD_RATS && receivedCmd_dec[1] == 0x80) {
|
||||
if (rats && rats_len) {
|
||||
if (encrypted_data) {
|
||||
memcpy(response, rats, rats_len);
|
||||
mf_crypto1_encrypt(pcs, response, rats_len, response_par);
|
||||
EmSendCmdPar(response, rats_len, response_par);
|
||||
} else
|
||||
EmSendCmd(rats, rats_len);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV RATS => ACK");
|
||||
} else {
|
||||
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV RATS => NACK");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// case MFEMUL_WORK => ISO14443A_CMD_NXP_DESELECT
|
||||
if (receivedCmd_len == 3 && receivedCmd_dec[0] == ISO14443A_CMD_NXP_DESELECT) {
|
||||
if (rats && rats_len) {
|
||||
// response back NXP_DESELECT
|
||||
if (encrypted_data) {
|
||||
memcpy(response, receivedCmd_dec, receivedCmd_len);
|
||||
mf_crypto1_encrypt(pcs, response, receivedCmd_len, response_par);
|
||||
EmSendCmdPar(response, receivedCmd_len, response_par);
|
||||
} else
|
||||
EmSendCmd(receivedCmd_dec, receivedCmd_len);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => ACK");
|
||||
} else {
|
||||
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => NACK");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -396,7 +396,7 @@ static int CmdrevengSearch(const char *Cmd) {
|
|||
uint8_t width[NMODELS] = {0};
|
||||
int count = 0;
|
||||
|
||||
uint8_t crcChars = 0;
|
||||
uint8_t crcChars;
|
||||
char result[30];
|
||||
char revResult[30];
|
||||
int ans = GetModels(Models, &count, width);
|
||||
|
|
|
@ -52,13 +52,13 @@ static int CmdHelp(const char *Cmd);
|
|||
static int CmdHFFidoInfo(const char *cmd) {
|
||||
|
||||
if (cmd && strlen(cmd) > 0)
|
||||
PrintAndLog("WARNING: command don't have any parameters.\n");
|
||||
PrintAndLogEx(WARNING, "WARNING: command don't have any parameters.\n");
|
||||
|
||||
// info about 14a part
|
||||
infoHF14A(false, false);
|
||||
|
||||
// FIDO info
|
||||
PrintAndLog("--------------------------------------------");
|
||||
PrintAndLogEx(NORMAL, "--------------------------------------------");
|
||||
SetAPDULogging(false);
|
||||
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
@ -73,9 +73,9 @@ static int CmdHFFidoInfo(const char *cmd) {
|
|||
|
||||
if (sw != 0x9000) {
|
||||
if (sw)
|
||||
PrintAndLog("Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(INFO, "Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
else
|
||||
PrintAndLog("APDU exchange error. Card returns 0x0000.");
|
||||
PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000.");
|
||||
|
||||
DropField();
|
||||
return 0;
|
||||
|
@ -83,14 +83,14 @@ static int CmdHFFidoInfo(const char *cmd) {
|
|||
|
||||
if (!strncmp((char *)buf, "U2F_V2", 7)) {
|
||||
if (!strncmp((char *)buf, "FIDO_2_0", 8)) {
|
||||
PrintAndLog("FIDO2 authenricator detected. Version: %.*s", len, buf);
|
||||
PrintAndLogEx(INFO, "FIDO2 authenricator detected. Version: %.*s", len, buf);
|
||||
} else {
|
||||
PrintAndLog("FIDO authenricator detected (not standard U2F).");
|
||||
PrintAndLog("Non U2F authenticator version:");
|
||||
PrintAndLogEx(INFO, "FIDO authenricator detected (not standard U2F).");
|
||||
PrintAndLogEx(INFO, "Non U2F authenticator version:");
|
||||
dump_buffer((const unsigned char *)buf, len, NULL, 0);
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("FIDO U2F authenricator detected. Version: %.*s", len, buf);
|
||||
PrintAndLogEx(INFO, "FIDO U2F authenricator detected. Version: %.*s", len, buf);
|
||||
}
|
||||
|
||||
res = FIDO2GetInfo(buf, sizeof(buf), &len, &sw);
|
||||
|
@ -99,28 +99,22 @@ static int CmdHFFidoInfo(const char *cmd) {
|
|||
return res;
|
||||
}
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("FIDO2 version not exists (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "FIDO2 version not exists (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buf[0]) {
|
||||
PrintAndLog("FIDO2 ger version error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
|
||||
PrintAndLogEx(ERR, "FIDO2 ger version error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > 1) {
|
||||
// if (false) {
|
||||
// PrintAndLog("FIDO2 version: (len=%d)", len);
|
||||
// dump_buffer((const unsigned char *)buf, len, NULL, 0);
|
||||
// }
|
||||
|
||||
PrintAndLog("FIDO2 version CBOR decoded:");
|
||||
PrintAndLogEx(SUCCESS, "FIDO2 version CBOR decoded:");
|
||||
TinyCborPrintFIDOPackage(fido2CmdGetInfo, true, &buf[1], len - 1);
|
||||
} else {
|
||||
PrintAndLog("FIDO2 version length error");
|
||||
PrintAndLogEx(ERR, "FIDO2 version length error");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -149,13 +143,13 @@ static json_t *OpenJson(int paramnum, char *fname, void *argtable[], bool *err)
|
|||
if (access(fname, F_OK) != -1) {
|
||||
root = json_load_file(fname, 0, &error);
|
||||
if (!root) {
|
||||
PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text);
|
||||
PrintAndLogEx(ERR, "ERROR: json error on line %d: %s", error.line, error.text);
|
||||
*err = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!json_is_object(root)) {
|
||||
PrintAndLog("ERROR: Invalid json format. root must be an object.");
|
||||
PrintAndLogEx(ERR, "ERROR: Invalid json format. root must be an object.");
|
||||
json_decref(root);
|
||||
*err = true;
|
||||
return NULL;
|
||||
|
@ -216,13 +210,13 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
memset(cdata, 0x00, 32);
|
||||
CLIGetStrWithReturn(6, cdata, &chlen);
|
||||
if (chlen > 16) {
|
||||
PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
|
||||
PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
CLIGetHexWithReturn(6, cdata, &chlen);
|
||||
if (chlen && chlen != 32) {
|
||||
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
|
||||
PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -234,13 +228,13 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
memset(adata, 0x00, 32);
|
||||
CLIGetStrWithReturn(7, adata, &applen);
|
||||
if (applen > 16) {
|
||||
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
|
||||
PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
CLIGetHexWithReturn(7, adata, &applen);
|
||||
if (applen && applen != 32) {
|
||||
PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
|
||||
PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -262,13 +256,13 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||
|
||||
if (res) {
|
||||
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
|
||||
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return 2;
|
||||
}
|
||||
|
@ -276,44 +270,44 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
res = FIDORegister(data, buf, sizeof(buf), &len, &sw);
|
||||
DropField();
|
||||
if (res) {
|
||||
PrintAndLog("Can't execute register command. res=%x. Exit...", res);
|
||||
PrintAndLogEx(ERR, "Can't execute register command. res=%x. Exit...", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return 3;
|
||||
}
|
||||
|
||||
PrintAndLog("");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
if (APDULogging)
|
||||
PrintAndLog("---------------------------------------------------------------");
|
||||
PrintAndLog("data len: %d", len);
|
||||
PrintAndLogEx(NORMAL, "---------------------------------------------------------------");
|
||||
PrintAndLogEx(NORMAL, "data len: %d", len);
|
||||
if (verbose2) {
|
||||
PrintAndLog("--------------data----------------------");
|
||||
PrintAndLogEx(NORMAL, "--------------data----------------------");
|
||||
dump_buffer((const unsigned char *)buf, len, NULL, 0);
|
||||
PrintAndLog("--------------data----------------------");
|
||||
PrintAndLogEx(NORMAL, "--------------data----------------------");
|
||||
}
|
||||
|
||||
if (buf[0] != 0x05) {
|
||||
PrintAndLog("ERROR: First byte must be 0x05, but it %2x", buf[0]);
|
||||
PrintAndLogEx(ERR, "ERROR: First byte must be 0x05, but it %2x", buf[0]);
|
||||
return 5;
|
||||
}
|
||||
PrintAndLog("User public key: %s", sprint_hex(&buf[1], 65));
|
||||
PrintAndLogEx(SUCCESS, "User public key: %s", sprint_hex(&buf[1], 65));
|
||||
|
||||
uint8_t keyHandleLen = buf[66];
|
||||
PrintAndLog("Key handle[%d]: %s", keyHandleLen, sprint_hex(&buf[67], keyHandleLen));
|
||||
PrintAndLogEx(SUCCESS, "Key handle[%d]: %s", keyHandleLen, sprint_hex(&buf[67], keyHandleLen));
|
||||
|
||||
int derp = 67 + keyHandleLen;
|
||||
int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4;
|
||||
if (verbose2) {
|
||||
PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen);
|
||||
PrintAndLogEx(NORMAL, "DER certificate[%d]:\n------------------DER-------------------", derLen);
|
||||
dump_buffer_simple((const unsigned char *)&buf[derp], derLen, NULL);
|
||||
PrintAndLog("\n----------------DER---------------------");
|
||||
PrintAndLogEx(NORMAL, "\n----------------DER---------------------");
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLog("------------------DER-------------------");
|
||||
PrintAndLog("DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20));
|
||||
PrintAndLogEx(NORMAL, "------------------DER-------------------");
|
||||
PrintAndLogEx(NORMAL, "DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20));
|
||||
}
|
||||
|
||||
// check and print DER certificate
|
||||
|
@ -321,16 +315,16 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
|
||||
// print DER certificate in TLV view
|
||||
if (showDERTLV) {
|
||||
PrintAndLog("----------------DER TLV-----------------");
|
||||
PrintAndLogEx(NORMAL, "----------------DER TLV-----------------");
|
||||
asn1_print(&buf[derp], derLen, " ");
|
||||
PrintAndLog("----------------DER TLV-----------------");
|
||||
PrintAndLogEx(NORMAL, "----------------DER TLV-----------------");
|
||||
}
|
||||
|
||||
FIDOCheckDERAndGetKey(&buf[derp], derLen, verbose, public_key, sizeof(public_key));
|
||||
|
||||
// get hash
|
||||
int hashp = 1 + 65 + 1 + keyHandleLen + derLen;
|
||||
PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp));
|
||||
PrintAndLogEx(SUCCESS, "Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp));
|
||||
|
||||
// check ANSI X9.62 format ECDSA signature (on P-256)
|
||||
uint8_t rval[300] = {0};
|
||||
|
@ -338,8 +332,8 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
res = ecdsa_asn1_get_signature(&buf[hashp], len - hashp, rval, sval);
|
||||
if (!res) {
|
||||
if (verbose) {
|
||||
PrintAndLog(" r: %s", sprint_hex(rval, 32));
|
||||
PrintAndLog(" s: %s", sprint_hex(sval, 32));
|
||||
PrintAndLogEx(NORMAL, " r: %s", sprint_hex(rval, 32));
|
||||
PrintAndLogEx(NORMAL, " s: %s", sprint_hex(sval, 32));
|
||||
}
|
||||
|
||||
uint8_t xbuf[4096] = {0};
|
||||
|
@ -351,23 +345,23 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
&buf[67], keyHandleLen, // keyHandle
|
||||
&buf[1], 65, // user public key
|
||||
NULL, 0);
|
||||
//PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
|
||||
//PrintAndLogEx(NORMAL, "--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
|
||||
res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[hashp], len - hashp);
|
||||
if (res) {
|
||||
if (res == -0x4e00) {
|
||||
PrintAndLog("Signature is NOT VALID.");
|
||||
PrintAndLogEx(WARNING, "Signature is NOT VALID.");
|
||||
} else {
|
||||
PrintAndLog("Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("Signature is OK.");
|
||||
PrintAndLogEx(SUCCESS, "Signature is OK.");
|
||||
}
|
||||
|
||||
} else {
|
||||
PrintAndLog("Invalid signature. res=%d.", res);
|
||||
PrintAndLogEx(WARNING, "Invalid signature. res = %d.", res);
|
||||
}
|
||||
|
||||
PrintAndLog("\nauth command: ");
|
||||
PrintAndLogEx(INFO, "\nauth command: ");
|
||||
printf("hf fido auth %s%s", paramsPlain ? "-p " : "", sprint_hex_inrow(&buf[67], keyHandleLen));
|
||||
if (chlen || applen)
|
||||
printf(" %s", paramsPlain ? (char *)cdata : sprint_hex_inrow(cdata, 32));
|
||||
|
@ -385,10 +379,10 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
|
||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: can't save the file: %s", fname);
|
||||
PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname);
|
||||
return 200;
|
||||
}
|
||||
PrintAndLog("File `%s` saved.", fname);
|
||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
||||
|
||||
// free json object
|
||||
json_decref(root);
|
||||
|
@ -457,7 +451,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
// public key
|
||||
CLIGetHexWithReturn(8, hdata, &hdatalen);
|
||||
if (hdatalen && hdatalen != 65) {
|
||||
PrintAndLog("ERROR: public key length must be 65 bytes only.");
|
||||
PrintAndLogEx(ERR, "ERROR: public key length must be 65 bytes only.");
|
||||
return 1;
|
||||
}
|
||||
if (hdatalen) {
|
||||
|
@ -467,7 +461,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
|
||||
CLIGetHexWithReturn(9, hdata, &hdatalen);
|
||||
if (hdatalen > 255) {
|
||||
PrintAndLog("ERROR: application parameter length must be less than 255.");
|
||||
PrintAndLogEx(ERR, "ERROR: application parameter length must be less than 255.");
|
||||
return 1;
|
||||
}
|
||||
if (hdatalen) {
|
||||
|
@ -480,13 +474,13 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
memset(hdata, 0x00, 32);
|
||||
CLIGetStrWithReturn(9, hdata, &hdatalen);
|
||||
if (hdatalen > 16) {
|
||||
PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
||||
PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
CLIGetHexWithReturn(10, hdata, &hdatalen);
|
||||
if (hdatalen && hdatalen != 32) {
|
||||
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
|
||||
PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -497,13 +491,13 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
memset(hdata, 0x00, 32);
|
||||
CLIGetStrWithReturn(11, hdata, &hdatalen);
|
||||
if (hdatalen > 16) {
|
||||
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
||||
PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
CLIGetHexWithReturn(10, hdata, &hdatalen);
|
||||
if (hdatalen && hdatalen != 32) {
|
||||
PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
|
||||
PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -530,13 +524,13 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||
|
||||
if (res) {
|
||||
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
|
||||
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return 2;
|
||||
}
|
||||
|
@ -544,20 +538,20 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
res = FIDOAuthentication(data, datalen, controlByte, buf, sizeof(buf), &len, &sw);
|
||||
DropField();
|
||||
if (res) {
|
||||
PrintAndLog("Can't execute authentication command. res=%x. Exit...", res);
|
||||
PrintAndLogEx(ERR, "Can't execute authentication command. res=%x. Exit...", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return 3;
|
||||
}
|
||||
|
||||
PrintAndLog("---------------------------------------------------------------");
|
||||
PrintAndLog("User presence: %s", (buf[0] ? "verified" : "not verified"));
|
||||
PrintAndLogEx(NORMAL, "---------------------------------------------------------------");
|
||||
PrintAndLogEx(SUCCESS, "User presence: %s", (buf[0] ? "verified" : "not verified"));
|
||||
uint32_t cntr = (uint32_t)bytes_to_num(&buf[1], 4);
|
||||
PrintAndLog("Counter: %d", cntr);
|
||||
PrintAndLog("Hash[%d]: %s", len - 5, sprint_hex(&buf[5], len - 5));
|
||||
PrintAndLogEx(SUCCESS, "Counter: %d", cntr);
|
||||
PrintAndLogEx(SUCCESS, "Hash[%d]: %s", len - 5, sprint_hex(&buf[5], len - 5));
|
||||
|
||||
// check ANSI X9.62 format ECDSA signature (on P-256)
|
||||
uint8_t rval[300] = {0};
|
||||
|
@ -565,8 +559,8 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
res = ecdsa_asn1_get_signature(&buf[5], len - 5, rval, sval);
|
||||
if (!res) {
|
||||
if (verbose) {
|
||||
PrintAndLog(" r: %s", sprint_hex(rval, 32));
|
||||
PrintAndLog(" s: %s", sprint_hex(sval, 32));
|
||||
PrintAndLogEx(NORMAL, " r: %s", sprint_hex(rval, 32));
|
||||
PrintAndLogEx(NORMAL, " s: %s", sprint_hex(sval, 32));
|
||||
}
|
||||
if (public_key_loaded) {
|
||||
uint8_t xbuf[4096] = {0};
|
||||
|
@ -577,22 +571,22 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
&buf[1], 4, // counter
|
||||
data, 32, // challenge parameter
|
||||
NULL, 0);
|
||||
//PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
|
||||
//PrintAndLogEx(NORMAL, "--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
|
||||
res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[5], len - 5);
|
||||
if (res) {
|
||||
if (res == -0x4e00) {
|
||||
PrintAndLog("Signature is NOT VALID.");
|
||||
PrintAndLogEx(WARNING, "Signature is NOT VALID.");
|
||||
} else {
|
||||
PrintAndLog("Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("Signature is OK.");
|
||||
PrintAndLogEx(SUCCESS, "Signature is OK.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("No public key provided. can't check signature.");
|
||||
PrintAndLogEx(WARNING, "No public key provided. can't check signature.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("Invalid signature. res=%d.", res);
|
||||
PrintAndLogEx(ERR, "Invalid signature. res = %d.", res);
|
||||
}
|
||||
|
||||
if (root) {
|
||||
|
@ -604,10 +598,10 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
|
||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: can't save the file: %s", fname);
|
||||
PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname);
|
||||
return 200;
|
||||
}
|
||||
PrintAndLog("File `%s` saved.", fname);
|
||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
||||
|
||||
// free json object
|
||||
json_decref(root);
|
||||
|
@ -691,13 +685,13 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
|||
|
||||
int res = GetExistsFileNameJson("fido", cjsonname, fname);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: Can't found the json file.");
|
||||
PrintAndLogEx(ERR, "ERROR: Can't found the json file.");
|
||||
return res;
|
||||
}
|
||||
PrintAndLog("fname: %s\n", fname);
|
||||
PrintAndLogEx(NORMAL, "fname: %s\n", fname);
|
||||
root = json_load_file(fname, 0, &error);
|
||||
if (!root) {
|
||||
PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text);
|
||||
PrintAndLogEx(ERR, "ERROR: json error on line %d: %s", error.line, error.text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -711,13 +705,13 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
|||
res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||
|
||||
if (res) {
|
||||
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
|
||||
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return 2;
|
||||
}
|
||||
|
@ -727,35 +721,35 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
|||
return res;
|
||||
|
||||
if (showCBOR) {
|
||||
PrintAndLog("CBOR make credentional request:");
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(INFO, "CBOR make credentional request:");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
TinyCborPrintFIDOPackage(fido2CmdMakeCredential, false, data, datalen);
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
}
|
||||
|
||||
res = FIDO2MakeCredential(data, datalen, buf, sizeof(buf), &len, &sw);
|
||||
DropField();
|
||||
if (res) {
|
||||
PrintAndLog("Can't execute make credential command. res=%x. Exit...", res);
|
||||
PrintAndLogEx(ERR, "Can't execute make credential command. res=%x. Exit...", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("ERROR execute make credential command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "ERROR execute make credential command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (buf[0]) {
|
||||
PrintAndLog("FIDO2 make credential error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
|
||||
PrintAndLogEx(ERR, "FIDO2 make credential error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
PrintAndLog("MakeCredential result (%d b) OK.", len);
|
||||
PrintAndLogEx(SUCCESS, "MakeCredential result (%d b) OK.", len);
|
||||
if (showCBOR) {
|
||||
PrintAndLog("CBOR make credentional response:");
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(SUCCESS, "CBOR make credentional response:");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
TinyCborPrintFIDOPackage(fido2CmdMakeCredential, true, &buf[1], len - 1);
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
}
|
||||
|
||||
// parse returned cbor
|
||||
|
@ -764,14 +758,13 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
|||
if (root) {
|
||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: can't save the file: %s", fname);
|
||||
PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname);
|
||||
return 200;
|
||||
}
|
||||
PrintAndLog("File `%s` saved.", fname);
|
||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
||||
}
|
||||
|
||||
json_decref(root);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
@ -818,13 +811,13 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
|||
|
||||
int res = GetExistsFileNameJson("fido", "fido2", fname);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: Can't found the json file.");
|
||||
PrintAndLogEx(ERR, "ERROR: Can't found the json file.");
|
||||
return res;
|
||||
}
|
||||
PrintAndLog("fname: %s\n", fname);
|
||||
PrintAndLogEx(NORMAL, "fname: %s\n", fname);
|
||||
root = json_load_file(fname, 0, &error);
|
||||
if (!root) {
|
||||
PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text);
|
||||
PrintAndLogEx(ERR, "ERROR: json error on line %d: %s", error.line, error.text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -838,13 +831,13 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
|||
res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||
|
||||
if (res) {
|
||||
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
|
||||
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return 2;
|
||||
}
|
||||
|
@ -854,35 +847,35 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
|||
return res;
|
||||
|
||||
if (showCBOR) {
|
||||
PrintAndLog("CBOR get assertion request:");
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(SUCCESS, "CBOR get assertion request:");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
TinyCborPrintFIDOPackage(fido2CmdGetAssertion, false, data, datalen);
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
}
|
||||
|
||||
res = FIDO2GetAssertion(data, datalen, buf, sizeof(buf), &len, &sw);
|
||||
DropField();
|
||||
if (res) {
|
||||
PrintAndLog("Can't execute get assertion command. res=%x. Exit...", res);
|
||||
PrintAndLogEx(ERR, "Can't execute get assertion command. res=%x. Exit...", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLog("ERROR execute get assertion command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
PrintAndLogEx(ERR, "ERROR execute get assertion command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (buf[0]) {
|
||||
PrintAndLog("FIDO2 get assertion error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
|
||||
PrintAndLogEx(ERR, "FIDO2 get assertion error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
PrintAndLog("GetAssertion result (%d b) OK.", len);
|
||||
PrintAndLogEx(SUCCESS, "GetAssertion result (%d b) OK.", len);
|
||||
if (showCBOR) {
|
||||
PrintAndLog("CBOR get assertion response:");
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(SUCCESS, "CBOR get assertion response:");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
TinyCborPrintFIDOPackage(fido2CmdGetAssertion, true, &buf[1], len - 1);
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
}
|
||||
|
||||
// parse returned cbor
|
||||
|
@ -891,14 +884,13 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
|||
if (root) {
|
||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: can't save the file: %s", fname);
|
||||
PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname);
|
||||
return 200;
|
||||
}
|
||||
PrintAndLog("File `%s` saved.", fname);
|
||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
||||
}
|
||||
|
||||
json_decref(root);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -64,14 +64,14 @@ static int usage_hf14_mifare(void) {
|
|||
PrintAndLogEx(NORMAL, " hf mf darkside 16 B");
|
||||
return 0;
|
||||
}
|
||||
static int usage_hf14_mf1ksim(void) {
|
||||
static int usage_hf14_mfsim(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mf sim [h] u <uid> n <numreads> [i] [x] [e] [v]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " u (Optional) UID 4,7 or 10bytes. If not specified, the UID 4b from emulator memory will be used");
|
||||
PrintAndLogEx(NORMAL, " t (Optional) 0 = MIFARE Mini");
|
||||
PrintAndLogEx(NORMAL, " 1 = MIFARE Classic 1k (Default)");
|
||||
PrintAndLogEx(NORMAL, " 1 = MIFARE Classic 2k");
|
||||
PrintAndLogEx(NORMAL, " 1 = MIFARE Classic 2k plus in SL0 mode");
|
||||
PrintAndLogEx(NORMAL, " 4 = MIFARE Classic 4k");
|
||||
PrintAndLogEx(NORMAL, " n (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite");
|
||||
PrintAndLogEx(NORMAL, " i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted");
|
||||
|
@ -2136,11 +2136,11 @@ void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose) {
|
|||
}
|
||||
}
|
||||
|
||||
static int CmdHF14AMf1kSim(const char *Cmd) {
|
||||
static int CmdHF14AMfSim(const char *Cmd) {
|
||||
|
||||
uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t exitAfterNReads = 0;
|
||||
uint16_t flags = (FLAG_UID_IN_EMUL | FLAG_4B_UID_IN_DATA);
|
||||
uint16_t flags = 0;
|
||||
int uidlen = 0;
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false, verbose = false, setEmulatorMem = false;
|
||||
|
@ -2153,7 +2153,7 @@ static int CmdHF14AMf1kSim(const char *Cmd) {
|
|||
cmdp++;
|
||||
break;
|
||||
case 'h':
|
||||
return usage_hf14_mf1ksim();
|
||||
return usage_hf14_mfsim();
|
||||
case 'i':
|
||||
flags |= FLAG_INTERACTIVE;
|
||||
cmdp++;
|
||||
|
@ -2191,16 +2191,16 @@ static int CmdHF14AMf1kSim(const char *Cmd) {
|
|||
param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen);
|
||||
switch (uidlen) {
|
||||
case 20:
|
||||
flags = FLAG_10B_UID_IN_DATA;
|
||||
flags |= FLAG_10B_UID_IN_DATA;
|
||||
break;
|
||||
case 14:
|
||||
flags = FLAG_7B_UID_IN_DATA;
|
||||
flags |= FLAG_7B_UID_IN_DATA;
|
||||
break;
|
||||
case 8:
|
||||
flags = FLAG_4B_UID_IN_DATA;
|
||||
flags |= FLAG_4B_UID_IN_DATA;
|
||||
break;
|
||||
default:
|
||||
return usage_hf14_mf1ksim();
|
||||
return usage_hf14_mfsim();
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
|
@ -2219,7 +2219,11 @@ static int CmdHF14AMf1kSim(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
//Validations
|
||||
if (errors) return usage_hf14_mf1ksim();
|
||||
if (errors) return usage_hf14_mfsim();
|
||||
|
||||
// Use UID, SAK, ATQA from EMUL, if uid not defined
|
||||
if ((flags & (FLAG_4B_UID_IN_DATA | FLAG_7B_UID_IN_DATA | FLAG_10B_UID_IN_DATA)) == 0)
|
||||
flags |= FLAG_UID_IN_EMUL;
|
||||
|
||||
PrintAndLogEx(NORMAL, " uid:%s, numreads:%d, flags:%d (0x%02x) "
|
||||
, (uidlen == 0) ? "N/A" : sprint_hex(uid, uidlen >> 1)
|
||||
|
@ -3550,7 +3554,7 @@ static command_t CommandTable[] = {
|
|||
{"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"},
|
||||
// {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"},
|
||||
{"-----------", CmdHelp, 0, ""},
|
||||
{"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"},
|
||||
{"sim", CmdHF14AMfSim, 0, "Simulate MIFARE card"},
|
||||
{"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"},
|
||||
{"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"},
|
||||
{"eset", CmdHF14AMfESet, 0, "Set simulator memory block"},
|
||||
|
|
|
@ -856,9 +856,7 @@ int EM4x50Read(const char *Cmd, bool verbose) {
|
|||
phaseoff = 0;
|
||||
|
||||
// now do it again to find the end
|
||||
end = skip;
|
||||
for (i += 3; i < j - 4 ; ++i) {
|
||||
end += tmpbuff[i];
|
||||
if (tmpbuff[i] >= clk * 3 - tol && tmpbuff[i] <= clk * 3 + tol) //3 clocks
|
||||
if (tmpbuff[i + 1] >= clk * 2 - tol && tmpbuff[i + 1] <= clk * 2 + tol) //2 clocks
|
||||
if (tmpbuff[i + 2] >= clk * 3 - tol && tmpbuff[i + 2] <= clk * 3 + tol) //3 clocks
|
||||
|
|
|
@ -200,23 +200,23 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
bool protocol_T15_present = false;
|
||||
|
||||
if (T0 & 0x10) {
|
||||
PrintAndLog("\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]);
|
||||
PrintAndLogEx(NORMAL, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x20) {
|
||||
PrintAndLog("\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]);
|
||||
PrintAndLogEx(NORMAL, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x40) {
|
||||
PrintAndLog("\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]);
|
||||
PrintAndLogEx(NORMAL, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x80) {
|
||||
uint8_t TD1 = atr[2 + T1len];
|
||||
PrintAndLog("\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f);
|
||||
PrintAndLogEx(NORMAL, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f);
|
||||
protocol_T0_present = false;
|
||||
if ((TD1 & 0x0f) == 0) {
|
||||
protocol_T0_present = true;
|
||||
|
@ -228,20 +228,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
T1len++;
|
||||
|
||||
if (TD1 & 0x10) {
|
||||
PrintAndLog("\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
PrintAndLogEx(NORMAL, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x20) {
|
||||
PrintAndLog("\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
PrintAndLogEx(NORMAL, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x40) {
|
||||
PrintAndLog("\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
PrintAndLogEx(NORMAL, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x80) {
|
||||
uint8_t TDi = atr[2 + T1len + TD1len];
|
||||
PrintAndLog("\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f);
|
||||
PrintAndLogEx(NORMAL, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f);
|
||||
if ((TDi & 0x0f) == 0) {
|
||||
protocol_T0_present = true;
|
||||
}
|
||||
|
@ -255,20 +255,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
while (nextCycle) {
|
||||
nextCycle = false;
|
||||
if (TDi & 0x10) {
|
||||
PrintAndLog("\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(NORMAL, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x20) {
|
||||
PrintAndLog("\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(NORMAL, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x40) {
|
||||
PrintAndLog("\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(NORMAL, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x80) {
|
||||
TDi = atr[2 + T1len + TD1len + TDilen];
|
||||
PrintAndLog("\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f);
|
||||
PrintAndLogEx(NORMAL, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f);
|
||||
TDilen++;
|
||||
|
||||
nextCycle = true;
|
||||
|
|
|
@ -64,7 +64,7 @@ void SendCommand(UsbCommand *c) {
|
|||
#endif
|
||||
|
||||
if (offline) {
|
||||
PrintAndLogEx(WARNING, "Sending bytes to Proxmark3 failed." _YELLOW_("offline") );
|
||||
PrintAndLogEx(WARNING, "Sending bytes to Proxmark3 failed." _YELLOW_("offline"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -384,13 +384,13 @@ __attribute__((force_align_arg_pointer))
|
|||
if (txBufferNGLen) { // NG packet
|
||||
if (!uart_send(sp, (uint8_t *) &txBufferNG, txBufferNGLen)) {
|
||||
//counter_to_offline++;
|
||||
PrintAndLogEx(WARNING, "sending bytes to Proxmark3 device" _RED_("failed") );
|
||||
PrintAndLogEx(WARNING, "sending bytes to Proxmark3 device" _RED_("failed"));
|
||||
}
|
||||
txBufferNGLen = 0;
|
||||
} else {
|
||||
if (!uart_send(sp, (uint8_t *) &txBuffer, sizeof(UsbCommand))) {
|
||||
//counter_to_offline++;
|
||||
PrintAndLogEx(WARNING, "sending bytes to Proxmark3 device" _RED_("failed") );
|
||||
PrintAndLogEx(WARNING, "sending bytes to Proxmark3 device" _RED_("failed"));
|
||||
}
|
||||
}
|
||||
txBuffer_pending = false;
|
||||
|
|
|
@ -46,7 +46,7 @@ static void ParamLoadDefaults(struct tlvdb *tlvRoot) {
|
|||
static void PrintChannel(EMVCommandChannel channel) {
|
||||
switch (channel) {
|
||||
case ECC_CONTACTLESS:
|
||||
PrintAndLogEx(INFO, "Channel: CONTACTLESS");
|
||||
PrintAndLogEx(INFO, "Channel: CONTACTLESS (T=CL)");
|
||||
break;
|
||||
case ECC_CONTACT:
|
||||
PrintAndLogEx(INFO, "Channel: CONTACT");
|
||||
|
@ -203,7 +203,6 @@ static int CmdEMVPPSE(const char *Cmd) {
|
|||
if (res)
|
||||
return res;
|
||||
|
||||
|
||||
if (decodeTLV)
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
|
||||
|
@ -288,6 +287,7 @@ static int CmdEMVGPO(const char *Cmd) {
|
|||
PrintAndLogEx(ERR, "Can't create PDOL data.");
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
if (pdol_data_tlv != &data_tlv);
|
||||
free(pdol_data_tlv);
|
||||
return 4;
|
||||
}
|
||||
|
@ -410,7 +410,7 @@ static int CmdEMVAC(const char *Cmd) {
|
|||
termDecision = EMVAC_ARQC;
|
||||
|
||||
if (termDecision == 0xff) {
|
||||
PrintAndLog("ERROR: can't find terminal decision '%s'", arg_get_str(3)->sval[0]);
|
||||
PrintAndLogEx(ERR, "ERROR: can't find terminal decision '%s'", arg_get_str(3)->sval[0]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
|
@ -647,7 +647,7 @@ static void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON,
|
|||
ParamLoadDefaults(tlvRoot);
|
||||
|
||||
if (paramLoadJSON) {
|
||||
PrintAndLog("* * Transaction parameters loading from JSON...");
|
||||
PrintAndLogEx(INFO, "* * Transaction parameters loading from JSON...");
|
||||
ParamLoadFromJson(tlvRoot);
|
||||
}
|
||||
|
||||
|
@ -678,12 +678,12 @@ static void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON,
|
|||
static void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) {
|
||||
if (buf[0] == 0x80) {
|
||||
if (decodeTLV) {
|
||||
PrintAndLog("GPO response format1:");
|
||||
PrintAndLogEx(SUCCESS, "GPO response format1:");
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
}
|
||||
|
||||
if (len < 4 || (len - 4) % 4) {
|
||||
PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len);
|
||||
PrintAndLogEx(ERR, "GPO response format 1 parsing error. length = %d", len);
|
||||
} else {
|
||||
// AIP
|
||||
struct tlvdb *f1AIP = tlvdb_fixed(0x82, 2, buf + 2);
|
||||
|
@ -708,7 +708,7 @@ static void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_
|
|||
static void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) {
|
||||
if (buf[0] == 0x80) {
|
||||
if (decodeTLV) {
|
||||
PrintAndLog("GPO response format1:");
|
||||
PrintAndLogEx(SUCCESS, "GPO response format 1:");
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
}
|
||||
|
||||
|
@ -719,7 +719,7 @@ static void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t
|
|||
} else {
|
||||
struct tlvdb *tlvElm = NULL;
|
||||
if (decodeTLV)
|
||||
PrintAndLog("\n------------ Format1 decoded ------------");
|
||||
PrintAndLogEx(NORMAL, "\n------------ Format1 decoded ------------");
|
||||
|
||||
// CID (Cryptogram Information Data)
|
||||
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f27, 1, &buf[2], &tlvElm);
|
||||
|
@ -873,23 +873,23 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
|
||||
if (decodeTLV)
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
PrintAndLog("* Selected.");
|
||||
PrintAndLogEx(NORMAL, "* Selected.");
|
||||
|
||||
PrintAndLog("\n* Init transaction parameters.");
|
||||
PrintAndLogEx(NORMAL, "\n* Init transaction parameters.");
|
||||
InitTransactionParameters(tlvRoot, paramLoadJSON, TrType, GenACGPO);
|
||||
TLVPrintFromTLV(tlvRoot); // TODO delete!!!
|
||||
|
||||
PrintAndLogEx(NORMAL, "\n* Calc PDOL.");
|
||||
pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
||||
if (!pdol_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create PDOL TLV.");
|
||||
PrintAndLogEx(ERR, "Error: can't create PDOL TLV.");
|
||||
dreturn(4);
|
||||
}
|
||||
|
||||
size_t pdol_data_tlv_data_len;
|
||||
unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
|
||||
if (!pdol_data_tlv_data) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create PDOL data.");
|
||||
PrintAndLogEx(ERR, "Error: can't create PDOL data.");
|
||||
dreturn(4);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
|
||||
|
@ -901,7 +901,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
//free(pdol_data_tlv); --- free on exit.
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(NORMAL, "GPO error(%d): %4x. Exit...", res, sw);
|
||||
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
|
||||
dreturn(5);
|
||||
}
|
||||
|
||||
|
@ -919,7 +919,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
const struct tlv *pantlv = tlvdb_get(tlvRoot, 0x5a, NULL);
|
||||
PrintAndLogEx(NORMAL, "\n* * Extracted PAN from track2: %s", sprint_hex(pantlv->value, pantlv->len));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "\n* * WARNING: Can't extract PAN from track2.");
|
||||
PrintAndLogEx(WARNING, "\n* * WARNING: Can't extract PAN from track2.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -928,7 +928,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL);
|
||||
|
||||
if (!AFL || !AFL->len)
|
||||
PrintAndLogEx(NORMAL, "WARNING: AFL not found.");
|
||||
PrintAndLogEx(WARNING, "WARNING: AFL not found.");
|
||||
|
||||
while (AFL && AFL->len) {
|
||||
if (AFL->len % 4) {
|
||||
|
@ -1066,11 +1066,11 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "* * Generate challenge");
|
||||
res = EMVGenerateChallenge(channel, true, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
if (res) {
|
||||
PrintAndLogEx(WARNING, "Error GetChallenge. APDU error %4x", sw);
|
||||
PrintAndLogEx(ERR, "Error GetChallenge. APDU error %4x", sw);
|
||||
dreturn(6);
|
||||
}
|
||||
if (len < 4) {
|
||||
PrintAndLogEx(WARNING, "Error GetChallenge. Wrong challenge length %d", len);
|
||||
PrintAndLogEx(ERR, "Error GetChallenge. Wrong challenge length %d", len);
|
||||
dreturn(6);
|
||||
}
|
||||
|
||||
|
@ -1085,7 +1085,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "* * Calc CDOL1");
|
||||
struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV.");
|
||||
PrintAndLogEx(ERR, "Error: can't create CDOL1 TLV.");
|
||||
dreturn(6);
|
||||
}
|
||||
|
||||
|
@ -1096,7 +1096,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
res = EMVAC(channel, true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw);
|
||||
PrintAndLogEx(ERR, "AC1 error(%d): %4x. Exit...", res, sw);
|
||||
dreturn(7);
|
||||
}
|
||||
|
||||
|
@ -1175,7 +1175,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
|
||||
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!udol_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create UDOL TLV.");
|
||||
PrintAndLogEx(ERR, "Error: can't create UDOL TLV.");
|
||||
dreturn(8);
|
||||
}
|
||||
|
||||
|
@ -1185,7 +1185,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
|
||||
res = MSCComputeCryptoChecksum(channel, true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
if (res) {
|
||||
PrintAndLogEx(WARNING, "Error Compute Crypto Checksum. APDU error %4x", sw);
|
||||
PrintAndLogEx(ERR, "Error Compute Crypto Checksum. APDU error %4x", sw);
|
||||
free(udol_data_tlv);
|
||||
dreturn(9);
|
||||
}
|
||||
|
@ -1198,7 +1198,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Error MSD: Track2 data not found.");
|
||||
PrintAndLogEx(ERR, "Error MSD: Track2 data not found.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1209,7 +1209,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "* * Calc CDOL1");
|
||||
struct tlv *cdol1_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol1_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV.");
|
||||
PrintAndLogEx(ERR, "Error: can't create CDOL1 TLV.");
|
||||
dreturn(6);
|
||||
}
|
||||
|
||||
|
@ -1220,7 +1220,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
res = EMVAC(channel, true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol1_data_tlv->value, cdol1_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw);
|
||||
PrintAndLogEx(ERR, "AC1 error(%d): %4x. Exit...", res, sw);
|
||||
free(cdol1_data_tlv);
|
||||
dreturn(7);
|
||||
}
|
||||
|
@ -1232,7 +1232,7 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
tlvdb_get_uint8(tlvRoot, 0x9f27, &CID);
|
||||
|
||||
// AC1 print result
|
||||
PrintAndLog("");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_AAC) PrintAndLogEx(INFO, "AC1 result: AAC (Transaction declined)");
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_TC) PrintAndLogEx(INFO, "AC1 result: TC (Transaction approved)");
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_ARQC) PrintAndLogEx(INFO, "AC1 result: ARQC (Online authorisation requested)");
|
||||
|
@ -1264,13 +1264,13 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "CVR length: %d", CVRlen);
|
||||
PrintAndLogEx(NORMAL, "CVR: %s", sprint_hex(&IAD->value[4], CVRlen));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "Wrong CVR length! CVR: %s", sprint_hex(&IAD->value[3], VDDlen - 2));
|
||||
PrintAndLogEx(WARNING, "Wrong CVR length! CVR: %s", sprint_hex(&IAD->value[3], VDDlen - 2));
|
||||
}
|
||||
}
|
||||
if (IDDlen)
|
||||
PrintAndLogEx(NORMAL, "IDD: %s", sprint_hex(&IAD->value[VDDlen + 1], IDDlen));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "Issuer Application Data (IAD) not found.");
|
||||
PrintAndLogEx(WARNING, "Issuer Application Data (IAD) not found.");
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "\n* * Processing online request");
|
||||
|
@ -1278,7 +1278,9 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
// authorization response code from acquirer
|
||||
const char HostResponse[] = "00"; // 0x3030
|
||||
size_t HostResponseLen = sizeof(HostResponse) - 1;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Host Response: `%s`", HostResponse);
|
||||
|
||||
tlvdb_change_or_add_node(tlvRoot, 0x8a, HostResponseLen, (const unsigned char *)HostResponse);
|
||||
|
||||
if (CryptoVersion == 10) {
|
||||
|
@ -1300,30 +1302,23 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "ARPC: n/a");
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "Application Cryptogram (AC) not found.");
|
||||
PrintAndLogEx(WARNING, "Application Cryptogram (AC) not found.");
|
||||
}
|
||||
|
||||
// here must be external authenticate, but we dont know ARPC
|
||||
|
||||
}
|
||||
|
||||
|
||||
// needs to send AC2 command (res == ARQC)
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_ARQC) {
|
||||
PrintAndLogEx(NORMAL, "\n* * Calc CDOL2");
|
||||
struct tlv *cdol2_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8d, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol2_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create CDOL2 TLV.");
|
||||
PrintAndLogEx(ERR, "Error: can't create CDOL2 TLV.");
|
||||
dreturn(6);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "CDOL2 data[%d]: %s", cdol2_data_tlv->len, sprint_hex(cdol2_data_tlv->value, cdol2_data_tlv->len));
|
||||
|
||||
//PrintAndLogEx(NORMAL, "* * AC2");
|
||||
|
||||
|
||||
// here must be AC2, but we dont make external authenticate (
|
||||
|
||||
/* // AC2
|
||||
PRINT_INDENT(level);
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_AAC2) fprintf(f, "\tAC2: AAC (Transaction declined)\n");
|
||||
|
@ -1332,7 +1327,6 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
if ((CID & EMVAC_AC2_MASK) == EMVAC_AC2_MASK) fprintf(f, "\tAC2: RFU\n");
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DropFieldEx(channel);
|
||||
|
@ -1409,7 +1403,7 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
#ifndef WITH_SMARTCARD
|
||||
// not compiled with smartcard functionality, we need to exit
|
||||
if (channel == ECC_CONTACT) {
|
||||
PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
|
||||
PrintAndLogEx(ERR, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -1652,7 +1646,7 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
|
||||
if (decodeTLV) {
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
PrintAndLog("");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
json_t *jsonelm = json_object();
|
||||
|
@ -1692,7 +1686,7 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
PrintAndLogEx(ERR, "Can't save the file: %s", fname);
|
||||
return 200;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "File `%s` saved.", fname);
|
||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
||||
|
||||
// free json object
|
||||
json_decref(root);
|
||||
|
@ -1807,7 +1801,7 @@ static int CmdEMVRoca(const char *Cmd) {
|
|||
return 5;
|
||||
}
|
||||
|
||||
PrintAndLog("\n* Init transaction parameters.");
|
||||
PrintAndLogEx(NORMAL, "\n* Init transaction parameters.");
|
||||
InitTransactionParameters(tlvRoot, true, TT_QVSDCMCHIP, false);
|
||||
|
||||
PrintAndLogEx(NORMAL, "-->Calc PDOL.");
|
||||
|
|
|
@ -253,20 +253,29 @@ static size_t crypto_pk_polarssl_get_nbits(const struct crypto_pk *_cp) {
|
|||
static unsigned char *crypto_pk_polarssl_get_parameter(const struct crypto_pk *_cp, unsigned param, size_t *plen) {
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
unsigned char *result = NULL;
|
||||
int res;
|
||||
switch (param) {
|
||||
// mod
|
||||
case 0:
|
||||
*plen = mbedtls_mpi_size(&cp->ctx.N);
|
||||
result = malloc(*plen);
|
||||
memset(result, 0x00, *plen);
|
||||
mbedtls_mpi_write_binary(&cp->ctx.N, result, *plen);
|
||||
res = mbedtls_mpi_write_binary(&cp->ctx.N, result, *plen);
|
||||
if (res < 0) {
|
||||
printf("Error write_binary.");
|
||||
result = 0;
|
||||
}
|
||||
break;
|
||||
// exp
|
||||
case 1:
|
||||
*plen = mbedtls_mpi_size(&cp->ctx.E);
|
||||
result = malloc(*plen);
|
||||
memset(result, 0x00, *plen);
|
||||
mbedtls_mpi_write_binary(&cp->ctx.E, result, *plen);
|
||||
res = mbedtls_mpi_write_binary(&cp->ctx.E, result, *plen);
|
||||
if (res < 0) {
|
||||
printf("Error write_binary.");
|
||||
result = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("Error get parameter. Param = %u", param);
|
||||
|
|
|
@ -152,10 +152,10 @@ int roca_self_test(void) {
|
|||
|
||||
|
||||
if (emv_rocacheck(keyp, 64, false)) {
|
||||
PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_("PASS"));
|
||||
PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_("PASS"));
|
||||
} else {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_("Fail"));
|
||||
PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_("Fail"));
|
||||
}
|
||||
|
||||
// negative
|
||||
|
|
|
@ -75,7 +75,7 @@ int JsonSaveJsonObject(json_t *root, const char *path, json_t *value) {
|
|||
|
||||
if (path[0] == '$') {
|
||||
if (json_path_set(root, path, value, 0, &error)) {
|
||||
PrintAndLog("ERROR: can't set json path: ", error.text);
|
||||
PrintAndLogEx(ERR, "ERROR: can't set json path: ", error.text);
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -151,12 +151,12 @@ int JsonSaveTLVElm(json_t *elm, const char *path, struct tlv *tlvelm, bool saveN
|
|||
|
||||
if (json_is_array(elm)) {
|
||||
if (json_array_append_new(elm, obj)) {
|
||||
PrintAndLog("ERROR: can't append array: %s", path);
|
||||
PrintAndLogEx(ERR, "ERROR: can't append array: %s", path);
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (json_path_set(elm, path, obj, 0, &error)) {
|
||||
PrintAndLog("ERROR: can't set json path: ", error.text);
|
||||
PrintAndLogEx(ERR, "ERROR: can't set json path: ", error.text);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ int JsonSaveTLVTree(json_t *root, json_t *elm, const char *path, struct tlvdb *t
|
|||
|
||||
// check
|
||||
if (!json_is_array(chjson)) {
|
||||
PrintAndLog("E->Internal logic error. `$.Childs` is not an array.");
|
||||
PrintAndLogEx(ERR, "E->Internal logic error. `$.Childs` is not an array.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -243,18 +243,18 @@ static bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t *buf
|
|||
|
||||
switch (param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) {
|
||||
case 1:
|
||||
PrintAndLog("%s Invalid HEX value.", errormsg);
|
||||
PrintAndLogEx(ERR, "%s Invalid HEX value.", errormsg);
|
||||
return false;
|
||||
case 2:
|
||||
PrintAndLog("%s Hex value too large.", errormsg);
|
||||
PrintAndLogEx(ERR, "%s Hex value too large.", errormsg);
|
||||
return false;
|
||||
case 3:
|
||||
PrintAndLog("%s Hex value must have even number of digits.", errormsg);
|
||||
PrintAndLogEx(ERR, "%s Hex value must have even number of digits.", errormsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buflen > maxbufferlen) {
|
||||
PrintAndLog("%s HEX length (%d) more than %d", errormsg, (bufferlen) ? *bufferlen : -1, maxbufferlen);
|
||||
PrintAndLogEx(ERR, "%s HEX length (%d) more than %d", errormsg, (bufferlen) ? *bufferlen : -1, maxbufferlen);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,7 @@ bool ParamLoadFromJson(struct tlvdb *tlv) {
|
|||
json_error_t error;
|
||||
|
||||
if (!tlv) {
|
||||
PrintAndLog("ERROR load params: tlv tree is NULL.");
|
||||
PrintAndLogEx(ERR, "ERROR load params: tlv tree is NULL.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -312,30 +312,30 @@ bool ParamLoadFromJson(struct tlvdb *tlv) {
|
|||
|
||||
root = json_load_file(fname, 0, &error);
|
||||
if (!root) {
|
||||
PrintAndLog("Load params: json error on line %d: %s", error.line, error.text);
|
||||
PrintAndLogEx(ERR, "Load params: json error on line " _YELLOW_("%d") ": %s", error.line, error.text);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!json_is_array(root)) {
|
||||
PrintAndLog("Load params: Invalid json format. root must be array.");
|
||||
PrintAndLogEx(ERR, "Load params: Invalid json format. root must be array.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintAndLog("Load params: json(%d) OK", json_array_size(root));
|
||||
PrintAndLogEx(SUCCESS, "Load params: json(%d) " _GREEN_("OK"), json_array_size(root));
|
||||
|
||||
for (int i = 0; i < json_array_size(root); i++) {
|
||||
json_t *data, *jtag, *jlength, *jvalue;
|
||||
|
||||
data = json_array_get(root, i);
|
||||
if (!json_is_object(data)) {
|
||||
PrintAndLog("Load params: data [%d] is not an object", i + 1);
|
||||
PrintAndLogEx(ERR, "Load params: data [%d] is not an object", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
jtag = json_object_get(data, "tag");
|
||||
if (!json_is_string(jtag)) {
|
||||
PrintAndLog("Load params: data [%d] tag is not a string", i + 1);
|
||||
PrintAndLogEx(ERR, "Load params: data [%d] tag is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ bool ParamLoadFromJson(struct tlvdb *tlv) {
|
|||
|
||||
jvalue = json_object_get(data, "value");
|
||||
if (!json_is_string(jvalue)) {
|
||||
PrintAndLog("Load params: data [%d] value is not a string", i + 1);
|
||||
PrintAndLogEx(ERR, "Load params: data [%d] value is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
@ -351,19 +351,19 @@ bool ParamLoadFromJson(struct tlvdb *tlv) {
|
|||
|
||||
jlength = json_object_get(data, "length");
|
||||
if (!json_is_number(jlength)) {
|
||||
PrintAndLog("Load params: data [%d] length is not a number", i + 1);
|
||||
PrintAndLogEx(ERR, "Load params: data [%d] length is not a number", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
int tlvLength = json_integer_value(jlength);
|
||||
if (tlvLength > 250) {
|
||||
PrintAndLog("Load params: data [%d] length more than 250", i + 1);
|
||||
PrintAndLogEx(ERR, "Load params: data [%d] length more than 250", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintAndLog("TLV param: %s[%d]=%s", tlvTag, tlvLength, tlvValue);
|
||||
PrintAndLogEx(SUCCESS, "TLV param: %s[%d]=%s", tlvTag, tlvLength, tlvValue);
|
||||
uint8_t buf[251] = {0};
|
||||
size_t buflen = 0;
|
||||
|
||||
|
@ -382,7 +382,7 @@ bool ParamLoadFromJson(struct tlvdb *tlv) {
|
|||
}
|
||||
|
||||
if (buflen != tlvLength) {
|
||||
PrintAndLog("Load params: data [%d] length of HEX must(%d) be identical to length in TLV param(%d)", i + 1, buflen, tlvLength);
|
||||
PrintAndLogEx(ERR, "Load params: data [%d] length of HEX must(%d) be identical to length in TLV param(%d)", i + 1, buflen, tlvLength);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -162,16 +162,16 @@ int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public
|
|||
size_t len;
|
||||
|
||||
if (verbose)
|
||||
PrintAndLog("----------- CBOR decode ----------------");
|
||||
PrintAndLogEx(NORMAL, "----------- CBOR decode ----------------");
|
||||
|
||||
// kty
|
||||
int res = CborMapGetKeyById(&parser, &map, data, datalen, 1);
|
||||
if (!res) {
|
||||
cbor_value_get_int64(&map, &i64);
|
||||
if (verbose)
|
||||
PrintAndLog("kty [%lld] %s", (long long)i64, GetCOSEktyDescription(i64));
|
||||
PrintAndLogEx(SUCCESS, "kty [%lld] %s", (long long)i64, GetCOSEktyDescription(i64));
|
||||
if (i64 != 2)
|
||||
PrintAndLog("ERROR: kty must be 2.");
|
||||
PrintAndLogEx(ERR, "ERROR: kty must be 2.");
|
||||
}
|
||||
|
||||
// algorithm
|
||||
|
@ -179,9 +179,9 @@ int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public
|
|||
if (!res) {
|
||||
cbor_value_get_int64(&map, &i64);
|
||||
if (verbose)
|
||||
PrintAndLog("algorithm [%lld] %s", (long long)i64, GetCOSEAlgDescription(i64));
|
||||
PrintAndLogEx(SUCCESS, "algorithm [%lld] %s", (long long)i64, GetCOSEAlgDescription(i64));
|
||||
if (i64 != -7)
|
||||
PrintAndLog("ERROR: algorithm must be -7.");
|
||||
PrintAndLogEx(ERR, "ERROR: algorithm must be -7.");
|
||||
}
|
||||
|
||||
// curve
|
||||
|
@ -189,9 +189,9 @@ int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public
|
|||
if (!res) {
|
||||
cbor_value_get_int64(&map, &i64);
|
||||
if (verbose)
|
||||
PrintAndLog("curve [%lld] %s", (long long)i64, GetCOSECurveDescription(i64));
|
||||
PrintAndLogEx(SUCCESS, "curve [%lld] %s", (long long)i64, GetCOSECurveDescription(i64));
|
||||
if (i64 != 1)
|
||||
PrintAndLog("ERROR: curve must be 1.");
|
||||
PrintAndLogEx(ERR, "ERROR: curve must be 1.");
|
||||
}
|
||||
|
||||
// plain key
|
||||
|
@ -203,9 +203,9 @@ int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public
|
|||
res = CborGetBinStringValue(&map, &public_key[1], 32, &len);
|
||||
cbor_check(res);
|
||||
if (verbose)
|
||||
PrintAndLog("x - coordinate [%d]: %s", len, sprint_hex(&public_key[1], 32));
|
||||
PrintAndLogEx(SUCCESS, "x - coordinate [%d]: %s", len, sprint_hex(&public_key[1], 32));
|
||||
if (len != 32)
|
||||
PrintAndLog("ERROR: x - coordinate length must be 32.");
|
||||
PrintAndLogEx(ERR, "ERROR: x - coordinate length must be 32.");
|
||||
}
|
||||
|
||||
// y - coordinate
|
||||
|
@ -214,9 +214,9 @@ int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public
|
|||
res = CborGetBinStringValue(&map, &public_key[33], 32, &len);
|
||||
cbor_check(res);
|
||||
if (verbose)
|
||||
PrintAndLog("y - coordinate [%d]: %s", len, sprint_hex(&public_key[33], 32));
|
||||
PrintAndLogEx(SUCCESS, "y - coordinate [%d]: %s", len, sprint_hex(&public_key[33], 32));
|
||||
if (len != 32)
|
||||
PrintAndLog("ERROR: y - coordinate length must be 32.");
|
||||
PrintAndLogEx(ERR, "ERROR: y - coordinate length must be 32.");
|
||||
}
|
||||
|
||||
// d - private key
|
||||
|
@ -226,11 +226,11 @@ int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public
|
|||
res = CborGetBinStringValue(&map, private_key, sizeof(private_key), &len);
|
||||
cbor_check(res);
|
||||
if (verbose)
|
||||
PrintAndLog("d - private key [%d]: %s", len, sprint_hex(private_key, len));
|
||||
PrintAndLogEx(SUCCESS, "d - private key [%d]: %s", len, sprint_hex(private_key, len));
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
PrintAndLog("----------- CBOR decode ----------------");
|
||||
PrintAndLogEx(NORMAL, "----------- CBOR decode ----------------");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -226,52 +226,52 @@ int FIDOCheckDERAndGetKey(uint8_t *der, size_t derLen, bool verbose, uint8_t *pu
|
|||
mbedtls_x509_crt_init(&cacert);
|
||||
res = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) additional_ca_pem, additional_ca_pem_len);
|
||||
if (res < 0) {
|
||||
PrintAndLog("ERROR: CA parse certificate returned -0x%x - %s", -res, ecdsa_get_error(res));
|
||||
PrintAndLogEx(ERR, "ERROR: CA parse certificate returned -0x%x - %s", -res, ecdsa_get_error(res));
|
||||
}
|
||||
if (verbose)
|
||||
PrintAndLog("CA load OK. %d skipped", res);
|
||||
PrintAndLogEx(SUCCESS, "CA load OK. %d skipped", res);
|
||||
|
||||
// load DER certificate from authenticator's data
|
||||
mbedtls_x509_crt cert;
|
||||
mbedtls_x509_crt_init(&cert);
|
||||
res = mbedtls_x509_crt_parse_der(&cert, der, derLen);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: DER parse returned 0x%x - %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
PrintAndLogEx(ERR, "ERROR: DER parse returned 0x%x - %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
}
|
||||
|
||||
// get certificate info
|
||||
char linfo[300] = {0};
|
||||
if (verbose) {
|
||||
mbedtls_x509_crt_info(linfo, sizeof(linfo), " ", &cert);
|
||||
PrintAndLog("DER certificate info:\n%s", linfo);
|
||||
PrintAndLogEx(SUCCESS, "DER certificate info:\n%s", linfo);
|
||||
}
|
||||
|
||||
// verify certificate
|
||||
uint32_t verifyflags = 0;
|
||||
res = mbedtls_x509_crt_verify(&cert, &cacert, NULL, NULL, &verifyflags, NULL, NULL);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: DER verify returned 0x%x - %s\n", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
PrintAndLogEx(ERR, "ERROR: DER verify returned 0x%x - %s\n", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
} else {
|
||||
PrintAndLog("Certificate OK.\n");
|
||||
PrintAndLogEx(SUCCESS, "Certificate OK.\n");
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
memset(linfo, 0x00, sizeof(linfo));
|
||||
mbedtls_x509_crt_verify_info(linfo, sizeof(linfo), " ", verifyflags);
|
||||
PrintAndLog("Verification info:\n%s", linfo);
|
||||
PrintAndLogEx(SUCCESS, "Verification info:\n%s", linfo);
|
||||
}
|
||||
|
||||
// get public key
|
||||
res = ecdsa_public_key_from_pk(&cert.pk, publicKey, publicKeyMaxLen);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: getting public key from certificate 0x%x - %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
PrintAndLogEx(ERR, "ERROR: getting public key from certificate 0x%x - %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLog("Got a public key from certificate:\n%s", sprint_hex_inrow(publicKey, 65));
|
||||
PrintAndLogEx(SUCCESS, "Got a public key from certificate:\n%s", sprint_hex_inrow(publicKey, 65));
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
PrintAndLog("------------------DER-------------------");
|
||||
PrintAndLogEx(NORMAL, "------------------DER-------------------");
|
||||
|
||||
mbedtls_x509_crt_free(&cert);
|
||||
mbedtls_x509_crt_free(&cacert);
|
||||
|
@ -362,15 +362,15 @@ static int FIDO2CheckSignature(json_t *root, uint8_t *publickey, uint8_t *sign,
|
|||
res = ecdsa_asn1_get_signature(sign, signLen, rval, sval);
|
||||
if (!res) {
|
||||
if (verbose) {
|
||||
PrintAndLog(" r: %s", sprint_hex(rval, 32));
|
||||
PrintAndLog(" s: %s", sprint_hex(sval, 32));
|
||||
PrintAndLogEx(NORMAL, " r: %s", sprint_hex(rval, 32));
|
||||
PrintAndLogEx(NORMAL, " s: %s", sprint_hex(sval, 32));
|
||||
}
|
||||
|
||||
uint8_t clientDataHash[32] = {0};
|
||||
size_t clientDataHashLen = 0;
|
||||
res = JsonLoadBufAsHex(root, "$.ClientDataHash", clientDataHash, sizeof(clientDataHash), &clientDataHashLen);
|
||||
if (res || clientDataHashLen != 32) {
|
||||
PrintAndLog("ERROR: Can't get clientDataHash from json!");
|
||||
PrintAndLogEx(ERR, "ERROR: Can't get clientDataHash from json!");
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -380,20 +380,20 @@ static int FIDO2CheckSignature(json_t *root, uint8_t *publickey, uint8_t *sign,
|
|||
authData, authDataLen, // rpIdHash[32] + flags[1] + signCount[4]
|
||||
clientDataHash, 32, // Hash of the serialized client data. "$.ClientDataHash" from json
|
||||
NULL, 0);
|
||||
//PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
|
||||
//PrintAndLogEx(NORMAL, "--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
|
||||
res = ecdsa_signature_verify(publickey, xbuf, xbuflen, sign, signLen);
|
||||
if (res) {
|
||||
if (res == -0x4e00) {
|
||||
PrintAndLog("Signature is NOT VALID.");
|
||||
PrintAndLogEx(WARNING, "Signature is NOT VALID.");
|
||||
} else {
|
||||
PrintAndLog("Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
PrintAndLog("Signature is OK.");
|
||||
PrintAndLogEx(SUCCESS, "Signature is OK.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("Invalid signature. res=%d.", res);
|
||||
PrintAndLogEx(ERR, "Invalid signature. res = %d.", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -415,7 +415,7 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
|||
|
||||
res = cbor_value_dup_text_string(&map, &buf, &n, &map);
|
||||
cbor_check(res);
|
||||
PrintAndLog("format: %s", buf);
|
||||
PrintAndLogEx(INFO, "format: %s", buf);
|
||||
free(buf);
|
||||
|
||||
// authData
|
||||
|
@ -431,43 +431,43 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
|||
memcpy(authData, ubuf, authDataLen);
|
||||
|
||||
if (verbose2) {
|
||||
PrintAndLog("authData[%d]: %s", n, sprint_hex_inrow(authData, authDataLen));
|
||||
PrintAndLogEx(INFO, "authData[%d]: %s", n, sprint_hex_inrow(authData, authDataLen));
|
||||
} else {
|
||||
PrintAndLog("authData[%d]: %s...", n, sprint_hex(authData, MIN(authDataLen, 16)));
|
||||
PrintAndLogEx(INFO, "authData[%d]: %s...", n, sprint_hex(authData, MIN(authDataLen, 16)));
|
||||
}
|
||||
|
||||
PrintAndLog("RP ID Hash: %s", sprint_hex(ubuf, 32));
|
||||
PrintAndLogEx(INFO, "RP ID Hash: %s", sprint_hex(ubuf, 32));
|
||||
|
||||
// check RP ID Hash
|
||||
if (CheckrpIdHash(root, ubuf)) {
|
||||
PrintAndLog("rpIdHash OK.");
|
||||
PrintAndLogEx(SUCCESS, "rpIdHash OK.");
|
||||
} else {
|
||||
PrintAndLog("rpIdHash ERROR!");
|
||||
PrintAndLogEx(ERR, "rpIdHash ERROR!");
|
||||
}
|
||||
|
||||
PrintAndLog("Flags 0x%02x:", ubuf[32]);
|
||||
PrintAndLogEx(INFO, "Flags 0x%02x:", ubuf[32]);
|
||||
if (!ubuf[32])
|
||||
PrintAndLog("none");
|
||||
PrintAndLogEx(SUCCESS, "none");
|
||||
if (ubuf[32] & 0x01)
|
||||
PrintAndLog("up - user presence result");
|
||||
PrintAndLogEx(SUCCESS, "up - user presence result");
|
||||
if (ubuf[32] & 0x04)
|
||||
PrintAndLog("uv - user verification (fingerprint scan or a PIN or ...) result");
|
||||
PrintAndLogEx(SUCCESS, "uv - user verification (fingerprint scan or a PIN or ...) result");
|
||||
if (ubuf[32] & 0x40)
|
||||
PrintAndLog("at - attested credential data included");
|
||||
PrintAndLogEx(SUCCESS, "at - attested credential data included");
|
||||
if (ubuf[32] & 0x80)
|
||||
PrintAndLog("ed - extension data included");
|
||||
PrintAndLogEx(SUCCESS, "ed - extension data included");
|
||||
|
||||
uint32_t cntr = (uint32_t)bytes_to_num(&ubuf[33], 4);
|
||||
PrintAndLog("Counter: %d", cntr);
|
||||
PrintAndLogEx(SUCCESS, "Counter: %d", cntr);
|
||||
JsonSaveInt(root, "$.AppData.Counter", cntr);
|
||||
|
||||
// attestation data
|
||||
PrintAndLog("AAGUID: %s", sprint_hex(&ubuf[37], 16));
|
||||
PrintAndLogEx(SUCCESS, "AAGUID: %s", sprint_hex(&ubuf[37], 16));
|
||||
JsonSaveBufAsHexCompact(root, "$.AppData.AAGUID", &ubuf[37], 16);
|
||||
|
||||
// Credential ID
|
||||
uint8_t cridlen = (uint16_t)bytes_to_num(&ubuf[53], 2);
|
||||
PrintAndLog("Credential id[%d]: %s", cridlen, sprint_hex_inrow(&ubuf[55], cridlen));
|
||||
PrintAndLogEx(SUCCESS, "Credential id[%d]: %s", cridlen, sprint_hex_inrow(&ubuf[55], cridlen));
|
||||
JsonSaveInt(root, "$.AppData.CredentialIdLen", cridlen);
|
||||
JsonSaveBufAsHexCompact(root, "$.AppData.CredentialId", &ubuf[55], cridlen);
|
||||
|
||||
|
@ -475,24 +475,24 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
|||
uint8_t coseKey[65] = {0};
|
||||
uint16_t cplen = n - 55 - cridlen;
|
||||
if (verbose2) {
|
||||
PrintAndLog("Credentional public key (COSE_KEY)[%d]: %s", cplen, sprint_hex_inrow(&ubuf[55 + cridlen], cplen));
|
||||
PrintAndLogEx(SUCCESS, "Credentional public key (COSE_KEY)[%d]: %s", cplen, sprint_hex_inrow(&ubuf[55 + cridlen], cplen));
|
||||
} else {
|
||||
PrintAndLog("Credentional public key (COSE_KEY)[%d]: %s...", cplen, sprint_hex(&ubuf[55 + cridlen], MIN(cplen, 16)));
|
||||
PrintAndLogEx(SUCCESS, "Credentional public key (COSE_KEY)[%d]: %s...", cplen, sprint_hex(&ubuf[55 + cridlen], MIN(cplen, 16)));
|
||||
}
|
||||
JsonSaveBufAsHexCompact(root, "$.AppData.COSE_KEY", &ubuf[55 + cridlen], cplen);
|
||||
|
||||
if (showCBOR) {
|
||||
PrintAndLog("COSE structure:");
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(INFO, "COSE structure:");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
TinyCborPrintFIDOPackage(fido2COSEKey, true, &ubuf[55 + cridlen], cplen);
|
||||
PrintAndLog("---------------- CBOR ------------------");
|
||||
PrintAndLogEx(NORMAL, "---------------- CBOR ------------------");
|
||||
}
|
||||
|
||||
res = COSEGetECDSAKey(&ubuf[55 + cridlen], cplen, verbose, coseKey);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: Can't get COSE_KEY.");
|
||||
PrintAndLogEx(ERR, "ERROR: Can't get COSE_KEY.");
|
||||
} else {
|
||||
PrintAndLog("COSE public key: %s", sprint_hex_inrow(coseKey, sizeof(coseKey)));
|
||||
PrintAndLogEx(SUCCESS, "COSE public key: %s", sprint_hex_inrow(coseKey, sizeof(coseKey)));
|
||||
JsonSaveBufAsHexCompact(root, "$.AppData.COSEPublicKey", coseKey, sizeof(coseKey));
|
||||
}
|
||||
|
||||
|
@ -518,7 +518,7 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
|||
cbor_check(res);
|
||||
if (!strcmp(key, "alg")) {
|
||||
cbor_value_get_int64(&mapsmt, &alg);
|
||||
PrintAndLog("Alg [%lld] %s", (long long)alg, GetCOSEAlgDescription(alg));
|
||||
PrintAndLogEx(INFO, "Alg [%lld] %s", (long long)alg, GetCOSEAlgDescription(alg));
|
||||
res = cbor_value_advance_fixed(&mapsmt);
|
||||
cbor_check(res);
|
||||
}
|
||||
|
@ -527,9 +527,9 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
|||
res = CborGetBinStringValue(&mapsmt, sign, sizeof(sign), &signLen);
|
||||
cbor_check(res);
|
||||
if (verbose2) {
|
||||
PrintAndLog("signature [%d]: %s", signLen, sprint_hex_inrow(sign, signLen));
|
||||
PrintAndLogEx(INFO, "signature [%d]: %s", signLen, sprint_hex_inrow(sign, signLen));
|
||||
} else {
|
||||
PrintAndLog("signature [%d]: %s...", signLen, sprint_hex(sign, MIN(signLen, 16)));
|
||||
PrintAndLogEx(INFO, "signature [%d]: %s...", signLen, sprint_hex(sign, MIN(signLen, 16)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,11 +537,11 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
|||
res = CborGetArrayBinStringValue(&mapsmt, der, sizeof(der), &derLen);
|
||||
cbor_check(res);
|
||||
if (verbose2) {
|
||||
PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen);
|
||||
PrintAndLogEx(NORMAL, "DER certificate[%d]:\n------------------DER-------------------", derLen);
|
||||
dump_buffer_simple((const unsigned char *)der, derLen, NULL);
|
||||
PrintAndLog("\n----------------DER---------------------");
|
||||
PrintAndLogEx(NORMAL, "\n----------------DER---------------------");
|
||||
} else {
|
||||
PrintAndLog("DER [%d]: %s...", derLen, sprint_hex(der, MIN(derLen, 16)));
|
||||
PrintAndLogEx(NORMAL, "DER [%d]: %s...", derLen, sprint_hex(der, MIN(derLen, 16)));
|
||||
}
|
||||
JsonSaveBufAsHexCompact(root, "$.AppData.DER", der, derLen);
|
||||
}
|
||||
|
@ -553,9 +553,9 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
|||
|
||||
// print DER certificate in TLV view
|
||||
if (showDERTLV) {
|
||||
PrintAndLog("----------------DER TLV-----------------");
|
||||
PrintAndLogEx(NORMAL, "----------------DER TLV-----------------");
|
||||
asn1_print(der, derLen, " ");
|
||||
PrintAndLog("----------------DER TLV-----------------");
|
||||
PrintAndLogEx(NORMAL, "----------------DER TLV-----------------");
|
||||
}
|
||||
FIDOCheckDERAndGetKey(der, derLen, verbose, public_key, sizeof(public_key));
|
||||
JsonSaveBufAsHexCompact(root, "$.AppData.DERPublicKey", public_key, sizeof(public_key));
|
||||
|
@ -664,14 +664,14 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
|||
char ctype[200] = {0};
|
||||
res = CborGetStringValue(&mapint, ctype, sizeof(ctype), &n);
|
||||
cbor_check(res);
|
||||
PrintAndLog("credential type: %s", ctype);
|
||||
PrintAndLogEx(SUCCESS, "credential type: %s", ctype);
|
||||
}
|
||||
|
||||
if (!strcmp(key, "id")) {
|
||||
uint8_t cid[200] = {0};
|
||||
res = CborGetBinStringValue(&mapint, cid, sizeof(cid), &n);
|
||||
cbor_check(res);
|
||||
PrintAndLog("credential id [%d]: %s", n, sprint_hex(cid, n));
|
||||
PrintAndLogEx(SUCCESS, "credential id [%d]: %s", n, sprint_hex(cid, n));
|
||||
}
|
||||
}
|
||||
res = cbor_value_leave_container(&map, &mapint);
|
||||
|
@ -690,34 +690,34 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
|||
memcpy(authData, ubuf, authDataLen);
|
||||
|
||||
if (verbose2) {
|
||||
PrintAndLog("authData[%d]: %s", n, sprint_hex_inrow(authData, authDataLen));
|
||||
PrintAndLogEx(INFO, "authData[%d]: %s", n, sprint_hex_inrow(authData, authDataLen));
|
||||
} else {
|
||||
PrintAndLog("authData[%d]: %s...", n, sprint_hex(authData, MIN(authDataLen, 16)));
|
||||
PrintAndLogEx(INFO, "authData[%d]: %s...", n, sprint_hex(authData, MIN(authDataLen, 16)));
|
||||
}
|
||||
|
||||
PrintAndLog("RP ID Hash: %s", sprint_hex(ubuf, 32));
|
||||
PrintAndLogEx(INFO, "RP ID Hash: %s", sprint_hex(ubuf, 32));
|
||||
|
||||
// check RP ID Hash
|
||||
if (CheckrpIdHash(root, ubuf)) {
|
||||
PrintAndLog("rpIdHash OK.");
|
||||
PrintAndLogEx(SUCCESS, "rpIdHash OK.");
|
||||
} else {
|
||||
PrintAndLog("rpIdHash ERROR!");
|
||||
PrintAndLogEx(ERR, "rpIdHash ERROR!");
|
||||
}
|
||||
|
||||
PrintAndLog("Flags 0x%02x:", ubuf[32]);
|
||||
PrintAndLogEx(INFO, "Flags 0x%02x:", ubuf[32]);
|
||||
if (!ubuf[32])
|
||||
PrintAndLog("none");
|
||||
PrintAndLogEx(SUCCESS, "none");
|
||||
if (ubuf[32] & 0x01)
|
||||
PrintAndLog("up - user presence result");
|
||||
PrintAndLogEx(SUCCESS, "up - user presence result");
|
||||
if (ubuf[32] & 0x04)
|
||||
PrintAndLog("uv - user verification (fingerprint scan or a PIN or ...) result");
|
||||
PrintAndLogEx(SUCCESS, "uv - user verification (fingerprint scan or a PIN or ...) result");
|
||||
if (ubuf[32] & 0x40)
|
||||
PrintAndLog("at - attested credential data included");
|
||||
PrintAndLogEx(SUCCESS, "at - attested credential data included");
|
||||
if (ubuf[32] & 0x80)
|
||||
PrintAndLog("ed - extension data included");
|
||||
PrintAndLogEx(SUCCESS, "ed - extension data included");
|
||||
|
||||
uint32_t cntr = (uint32_t)bytes_to_num(&ubuf[33], 4);
|
||||
PrintAndLog("Counter: %d", cntr);
|
||||
PrintAndLogEx(SUCCESS, "Counter: %d", cntr);
|
||||
JsonSaveInt(root, "$.AppData.Counter", cntr);
|
||||
|
||||
free(ubuf);
|
||||
|
@ -725,7 +725,7 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
|||
// publicKeyCredentialUserEntity
|
||||
res = CborMapGetKeyById(&parser, &map, data, dataLen, 4);
|
||||
if (res) {
|
||||
PrintAndLog("UserEntity n/a");
|
||||
PrintAndLogEx(SUCCESS, "UserEntity n/a");
|
||||
} else {
|
||||
res = cbor_value_enter_container(&map, &mapint);
|
||||
cbor_check(res);
|
||||
|
@ -739,14 +739,14 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
|||
char cname[200] = {0};
|
||||
res = CborGetStringValue(&mapint, cname, sizeof(cname), &n);
|
||||
cbor_check(res);
|
||||
PrintAndLog("UserEntity %s: %s", key, cname);
|
||||
PrintAndLogEx(SUCCESS, "UserEntity %s: %s", key, cname);
|
||||
}
|
||||
|
||||
if (!strcmp(key, "id")) {
|
||||
uint8_t cid[200] = {0};
|
||||
res = CborGetBinStringValue(&mapint, cid, sizeof(cid), &n);
|
||||
cbor_check(res);
|
||||
PrintAndLog("UserEntity id [%d]: %s", n, sprint_hex(cid, n));
|
||||
PrintAndLogEx(SUCCESS, "UserEntity id [%d]: %s", n, sprint_hex(cid, n));
|
||||
|
||||
// check
|
||||
uint8_t idbuf[100] = {0};
|
||||
|
@ -755,9 +755,9 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
|||
JsonLoadBufAsHex(root, "$.UserEntity.id", idbuf, sizeof(idbuf), &idbuflen);
|
||||
|
||||
if (idbuflen == n && !memcmp(idbuf, cid, idbuflen)) {
|
||||
PrintAndLog("UserEntity id OK.");
|
||||
PrintAndLogEx(SUCCESS, "UserEntity id OK.");
|
||||
} else {
|
||||
PrintAndLog("ERROR: Wrong UserEntity id (from json: %s)", sprint_hex(idbuf, idbuflen));
|
||||
PrintAndLogEx(ERR, "ERROR: Wrong UserEntity id (from json: %s)", sprint_hex(idbuf, idbuflen));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -778,9 +778,9 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
|||
|
||||
cbor_check(res);
|
||||
if (verbose2) {
|
||||
PrintAndLog("signature [%d]: %s", signLen, sprint_hex_inrow(sign, signLen));
|
||||
PrintAndLogEx(SUCCESS, "signature [%d]: %s", signLen, sprint_hex_inrow(sign, signLen));
|
||||
} else {
|
||||
PrintAndLog("signature [%d]: %s...", signLen, sprint_hex(sign, MIN(signLen, 16)));
|
||||
PrintAndLogEx(SUCCESS, "signature [%d]: %s...", signLen, sprint_hex(sign, MIN(signLen, 16)));
|
||||
}
|
||||
|
||||
// get public key from json
|
||||
|
@ -796,11 +796,11 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
|||
// numberOfCredentials
|
||||
res = CborMapGetKeyById(&parser, &map, data, dataLen, 5);
|
||||
if (res) {
|
||||
PrintAndLog("numberOfCredentials: 1 by default");
|
||||
PrintAndLogEx(SUCCESS, "numberOfCredentials: 1 by default");
|
||||
} else {
|
||||
int64_t numberOfCredentials = 0;
|
||||
cbor_value_get_int64(&map, &numberOfCredentials);
|
||||
PrintAndLog("numberOfCredentials: %lld", (long long)numberOfCredentials);
|
||||
PrintAndLogEx(SUCCESS, "numberOfCredentials: %lld", (long long)numberOfCredentials);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -22,7 +22,7 @@ void jsonp_error_set_source(json_error_t *error, const char *source) {
|
|||
|
||||
length = strlen(source);
|
||||
if (length < JSON_ERROR_SOURCE_LENGTH) {
|
||||
strncpy(error->source, source, JSON_ERROR_SOURCE_LENGTH);
|
||||
strncpy(error->source, source, JSON_ERROR_SOURCE_LENGTH - 1);
|
||||
} else {
|
||||
size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4;
|
||||
memcpy(error->source, "...", 3);
|
||||
|
|
|
@ -65,9 +65,15 @@ static RetType write_to_buffer(void *cookie, const char *data, LenType len) {
|
|||
if (newsize >= b->alloc) { // NB! one extra byte is needed to avoid buffer overflow at close_buffer
|
||||
// make room
|
||||
size_t newalloc = newsize + newsize / 2 + 1; // give 50% more room
|
||||
ptr = realloc(ptr, newalloc);
|
||||
if (ptr == NULL)
|
||||
|
||||
char *tmp = realloc(ptr, newalloc);
|
||||
if (tmp == NULL) {
|
||||
free(ptr);
|
||||
return -1;
|
||||
} else {
|
||||
ptr = tmp;
|
||||
}
|
||||
|
||||
b->alloc = newalloc;
|
||||
*b->ptr = ptr;
|
||||
}
|
||||
|
|
|
@ -151,6 +151,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define ISO14443A_CMD_WRITEBLOCK 0xA0
|
||||
#define ISO14443A_CMD_HALT 0x50
|
||||
#define ISO14443A_CMD_RATS 0xE0
|
||||
#define ISO14443A_CMD_NXP_DESELECT 0xC2
|
||||
|
||||
#define MIFARE_SELECT_CT 0x88
|
||||
#define MIFARE_AUTH_KEYA 0x60
|
||||
|
@ -167,7 +168,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define MIFARE_EV1_SETMODE 0x43
|
||||
|
||||
#define MIFARE_ULC_WRITE 0xA2
|
||||
#define MIFARE_ULC_COMP_WRITE 0xA0
|
||||
#define MIFARE_ULC_COMP_WRITE 0xA0
|
||||
#define MIFARE_ULC_AUTH_1 0x1A
|
||||
#define MIFARE_ULC_AUTH_2 0xAF
|
||||
|
||||
|
|
Loading…
Reference in a new issue