mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-22 14:23:50 -07:00
Merge pull request #2030 from gm3197/smartcard-relay
[WIP] Use proxmark3 as standard PCSC smartcard reader
This commit is contained in:
commit
104744d007
12 changed files with 231 additions and 14 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...
|
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]
|
## [unreleased][unreleased]
|
||||||
|
- Use proxmark3 as a generic smartcard reader with other software with `smart relay` (@gm3197)
|
||||||
- Added `tools\mfkeys\staticnested` - program to recover static nested keys (@iceman1001)
|
- Added `tools\mfkeys\staticnested` - program to recover static nested keys (@iceman1001)
|
||||||
- Added `pm3_gen_dictionary.py` - python script to extract and save all keys from MFC dump files. (@iceman1001)
|
- Added `pm3_gen_dictionary.py` - python script to extract and save all keys from MFC dump files. (@iceman1001)
|
||||||
- Changed `hf mfu info` - now detect MIFARE Ultralight AES (@iceman1001)
|
- Changed `hf mfu info` - now detect MIFARE Ultralight AES (@iceman1001)
|
||||||
|
|
|
@ -43,6 +43,7 @@ add_library(pm3rrg_rdv4_mbedtls STATIC
|
||||||
../../common/mbedtls/x509.c
|
../../common/mbedtls/x509.c
|
||||||
../../common/mbedtls/x509_crl.c
|
../../common/mbedtls/x509_crl.c
|
||||||
../../common/mbedtls/x509_crt.c
|
../../common/mbedtls/x509_crt.c
|
||||||
|
../../common/mbedtls/net_sockets.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(pm3rrg_rdv4_mbedtls PRIVATE ../../common)
|
target_include_directories(pm3rrg_rdv4_mbedtls PRIVATE ../../common)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "cmdparser.h" // command_t
|
#include "cmdparser.h" // command_t
|
||||||
#include "commonutil.h" // ARRAYLEN
|
#include "commonutil.h" // ARRAYLEN
|
||||||
|
#include "iso7816/iso7816core.h"
|
||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "cmdtrace.h"
|
#include "cmdtrace.h"
|
||||||
#include "proxmark3.h"
|
#include "proxmark3.h"
|
||||||
|
@ -32,6 +33,11 @@
|
||||||
#include "crc16.h" // crc
|
#include "crc16.h" // crc
|
||||||
#include "cliparser.h" // cliparsing
|
#include "cliparser.h" // cliparsing
|
||||||
#include "atrs.h" // ATR lookup
|
#include "atrs.h" // ATR lookup
|
||||||
|
#include "mbedtls/net_sockets.h"
|
||||||
|
#include "mifare.h"
|
||||||
|
#include "util_posix.h"
|
||||||
|
#include "cmdhf14a.h"
|
||||||
|
#include "cmdhf14b.h"
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
@ -1158,10 +1164,201 @@ static int CmdSmartBruteforceSFI(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void atsToEmulatedAtr(uint8_t *ats, uint8_t *atr, int *atrLen) {
|
||||||
|
int historicalLen = 0;
|
||||||
|
int offset = 2;
|
||||||
|
|
||||||
|
if (ats[0] < 2) {
|
||||||
|
historicalLen = 0;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ((ats[1] & 64) != 0) {
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
if ((ats[1] & 32) != 0) {
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
if ((ats[1] & 16) != 0) {
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset >= ats[0]) {
|
||||||
|
historicalLen = 0;
|
||||||
|
} else {
|
||||||
|
historicalLen = ats[0] - offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
atr[0] = 0x3B;
|
||||||
|
atr[1] = 0x80 | historicalLen;
|
||||||
|
atr[2] = 0x80;
|
||||||
|
atr[3] = 0x01;
|
||||||
|
|
||||||
|
uint8_t tck = atr[1] ^ atr[2] ^ atr[3];
|
||||||
|
for (int i = 0; i < historicalLen; ++i) {
|
||||||
|
atr[4 + i] = ats[offset + i];
|
||||||
|
tck = tck ^ ats[offset + i];
|
||||||
|
}
|
||||||
|
atr[4 + historicalLen] = tck;
|
||||||
|
|
||||||
|
*atrLen = 5 + historicalLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void atqbToEmulatedAtr(uint8_t *atqb, uint8_t cid, uint8_t *atr, int *atrLen) {
|
||||||
|
atr[0] = 0x3B;
|
||||||
|
atr[1] = 0x80 | 8;
|
||||||
|
atr[2] = 0x80;
|
||||||
|
atr[3] = 0x01;
|
||||||
|
|
||||||
|
memcpy(atr + 4, atqb, 7);
|
||||||
|
atr[11] = cid >> 4;
|
||||||
|
|
||||||
|
uint8_t tck = 0;
|
||||||
|
for (int i = 1; i < 12; ++i) {
|
||||||
|
tck = tck ^ atr[i];
|
||||||
|
}
|
||||||
|
atr[12] = tck;
|
||||||
|
|
||||||
|
*atrLen = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdRelay(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "smart relay",
|
||||||
|
"Make pm3 available to host OS smartcard driver via vpcd to enable use with other software such as GlobalPlatform Pro",
|
||||||
|
"Requires the virtual smartcard daemon to be installed and running, see https://frankmorgner.github.io/vsmartcard/virtualsmartcard/README.html"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0(NULL, "host", "<str>", "vpcd socket host (default: localhost)"),
|
||||||
|
arg_str0("p", "port", "<int>", "vpcd socket port (default: 35963)"),
|
||||||
|
arg_lit0("v", "verbose", "display APDU transactions between OS and card"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
|
uint8_t host[100] = {0};
|
||||||
|
int hostLen = sizeof(host);
|
||||||
|
CLIGetStrWithReturn(ctx, 1, host, &hostLen);
|
||||||
|
if (hostLen == 0) {
|
||||||
|
strcpy((char *) host, "localhost");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t port[6] = {0};
|
||||||
|
int portLen = sizeof(port);
|
||||||
|
CLIGetStrWithReturn(ctx, 2, port, &portLen);
|
||||||
|
if (portLen == 0) {
|
||||||
|
strcpy((char *) port, "35963");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool verbose = arg_get_lit(ctx, 3);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
mbedtls_net_context netCtx;
|
||||||
|
mbedtls_net_init(&netCtx);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Relaying pm3 to host OS pcsc daemon. Press " _GREEN_("Enter") " to exit");
|
||||||
|
|
||||||
|
uint8_t cmdbuf[512] = {0};
|
||||||
|
iso14a_card_select_t selectedCard14a;
|
||||||
|
iso14b_card_select_t selectedCard14b;
|
||||||
|
isodep_state_t cardType = ISODEP_INACTIVE;
|
||||||
|
bool fieldActivated = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (cardType != ISODEP_INACTIVE) {
|
||||||
|
int bytesRead = mbedtls_net_recv_timeout(&netCtx, cmdbuf, sizeof(cmdbuf), 100);
|
||||||
|
|
||||||
|
if (bytesRead == MBEDTLS_ERR_SSL_TIMEOUT || bytesRead == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesRead > 0) {
|
||||||
|
if (cmdbuf[1] == 0x01 && cmdbuf[2] == 0x04) { // vpcd GET ATR
|
||||||
|
uint8_t atr[20] = {0};
|
||||||
|
int atrLen = 0;
|
||||||
|
|
||||||
|
if (cardType == ISODEP_NFCA) {
|
||||||
|
atsToEmulatedAtr(selectedCard14a.ats, atr, &atrLen);
|
||||||
|
} else if (cardType == ISODEP_NFCB) {
|
||||||
|
atqbToEmulatedAtr(selectedCard14b.atqb, selectedCard14b.cid, atr, &atrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t res[22] = {0};
|
||||||
|
res[1] = atrLen;
|
||||||
|
memcpy(res + 2, atr, atrLen);
|
||||||
|
mbedtls_net_send(&netCtx, res, 2 + atrLen);
|
||||||
|
} else if (cmdbuf[1] != 0x01) { // vpcd APDU
|
||||||
|
int apduLen = (cmdbuf[0] << 8) + cmdbuf[1];
|
||||||
|
|
||||||
|
uint8_t apduRes[APDU_RES_LEN] = {0};
|
||||||
|
int apduResLen = 0;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, ">> %s", sprint_hex(cmdbuf + 2, apduLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardType == ISODEP_NFCA) {
|
||||||
|
if (ExchangeAPDU14a(cmdbuf + 2, apduLen, !fieldActivated, true, apduRes, sizeof(apduRes), &apduResLen) != PM3_SUCCESS) {
|
||||||
|
cardType = ISODEP_INACTIVE;
|
||||||
|
mbedtls_net_close(&netCtx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (cardType == ISODEP_NFCB) {
|
||||||
|
if (exchange_14b_apdu(cmdbuf + 2, apduLen, !fieldActivated, true, apduRes, sizeof(apduRes), &apduResLen, 0)) {
|
||||||
|
cardType = ISODEP_INACTIVE;
|
||||||
|
mbedtls_net_close(&netCtx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldActivated = true;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, "<< %s", sprint_hex(apduRes, apduResLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t res[APDU_RES_LEN + 2] = {0};
|
||||||
|
res[0] = (apduResLen >> 8) & 0xFF;
|
||||||
|
res[1] = apduResLen & 0xFF;
|
||||||
|
memcpy(res + 2, apduRes, apduResLen);
|
||||||
|
mbedtls_net_send(&netCtx, res, 2 + apduResLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (IfPm3Iso14443a() && SelectCard14443A_4(false, false, &selectedCard14a) == PM3_SUCCESS) {
|
||||||
|
cardType = ISODEP_NFCA;
|
||||||
|
} else if (IfPm3Iso14443b() && select_card_14443b_4(false, &selectedCard14b) == PM3_SUCCESS) {
|
||||||
|
cardType = ISODEP_NFCB;
|
||||||
|
}
|
||||||
|
if (cardType != ISODEP_INACTIVE) {
|
||||||
|
fieldActivated = false;
|
||||||
|
if (mbedtls_net_connect(&netCtx, (char *) host, (char *) port, MBEDTLS_NET_PROTO_TCP)) {
|
||||||
|
PrintAndLogEx(FAILED, "Failed to connect to vpcd socket. Ensure you have vpcd installed and running");
|
||||||
|
mbedtls_net_close(&netCtx);
|
||||||
|
mbedtls_net_free(&netCtx);
|
||||||
|
DropField();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msleep(300);
|
||||||
|
}
|
||||||
|
} while (!kbd_enter_pressed());
|
||||||
|
|
||||||
|
mbedtls_net_close(&netCtx);
|
||||||
|
mbedtls_net_free(&netCtx);
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
{"list", CmdSmartList, AlwaysAvailable, "List ISO 7816 history"},
|
{"list", CmdSmartList, AlwaysAvailable, "List ISO 7816 history"},
|
||||||
{"info", CmdSmartInfo, IfPm3Smartcard, "Tag information"},
|
{"info", CmdSmartInfo, IfPm3Smartcard, "Tag information"},
|
||||||
|
{"relay", CmdRelay, IfPm3Iso14443a, "Turn pm3 into pcsc reader and relay to host OS via vpcd"},
|
||||||
{"reader", CmdSmartReader, IfPm3Smartcard, "Act like an IS07816 reader"},
|
{"reader", CmdSmartReader, IfPm3Smartcard, "Act like an IS07816 reader"},
|
||||||
{"raw", CmdSmartRaw, IfPm3Smartcard, "Send raw hex data to tag"},
|
{"raw", CmdSmartRaw, IfPm3Smartcard, "Send raw hex data to tag"},
|
||||||
{"upgrade", CmdSmartUpgrade, AlwaysAvailable, "Upgrade sim module firmware"},
|
{"upgrade", CmdSmartUpgrade, AlwaysAvailable, "Upgrade sim module firmware"},
|
||||||
|
|
|
@ -791,6 +791,7 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 1, "smart help" },
|
{ 1, "smart help" },
|
||||||
{ 1, "smart list" },
|
{ 1, "smart list" },
|
||||||
{ 0, "smart info" },
|
{ 0, "smart info" },
|
||||||
|
{ 0, "smart relay" },
|
||||||
{ 0, "smart reader" },
|
{ 0, "smart reader" },
|
||||||
{ 0, "smart raw" },
|
{ 0, "smart raw" },
|
||||||
{ 1, "smart upgrade" },
|
{ 1, "smart upgrade" },
|
||||||
|
|
|
@ -46,7 +46,8 @@ MYSRCS = \
|
||||||
threading.c \
|
threading.c \
|
||||||
x509.c \
|
x509.c \
|
||||||
x509_crl.c \
|
x509_crl.c \
|
||||||
x509_crt.c
|
x509_crt.c \
|
||||||
|
net_sockets.c
|
||||||
|
|
||||||
LIB_A = libmbedtls.a
|
LIB_A = libmbedtls.a
|
||||||
|
|
||||||
|
|
|
@ -2979,7 +2979,7 @@
|
||||||
*
|
*
|
||||||
* This module provides networking routines.
|
* This module provides networking routines.
|
||||||
*/
|
*/
|
||||||
//#define MBEDTLS_NET_C
|
#define MBEDTLS_NET_C
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \def MBEDTLS_OID_C
|
* \def MBEDTLS_OID_C
|
||||||
|
|
|
@ -11790,6 +11790,21 @@
|
||||||
],
|
],
|
||||||
"usage": "smart reader [-hv]"
|
"usage": "smart reader [-hv]"
|
||||||
},
|
},
|
||||||
|
"smart relay": {
|
||||||
|
"command": "smart relay",
|
||||||
|
"description": "Make pm3 available to host OS smartcard driver via vpcd to enable use with other software such as GlobalPlatform Pro",
|
||||||
|
"notes": [
|
||||||
|
"Requires the virtual smartcard daemon to be installed and running, see https://frankmorgner.github.io/vsmartcard/virtualsmartcard/README.html"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help",
|
||||||
|
"--host <str> vpcd socket host (default: localhost)",
|
||||||
|
"-p, --port <int> vpcd socket port (default: 35963)",
|
||||||
|
"-v, --verbose display APDU transactions between OS and card"
|
||||||
|
],
|
||||||
|
"usage": "smart relay [-hv] [--host <str>] [-p <int>]"
|
||||||
|
},
|
||||||
"smart setclock": {
|
"smart setclock": {
|
||||||
"command": "smart setclock",
|
"command": "smart setclock",
|
||||||
"description": "Set clock speed for smart card interface.",
|
"description": "Set clock speed for smart card interface.",
|
||||||
|
@ -12049,8 +12064,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"commands_extracted": 698,
|
"commands_extracted": 699,
|
||||||
"extracted_by": "PM3Help2JSON v1.00",
|
"extracted_by": "PM3Help2JSON v1.00",
|
||||||
"extracted_on": "2023-11-09T16:29:08"
|
"extracted_on": "2023-11-11T20:31:02"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1424,6 +1424,7 @@ Check column "offline" for their availability.
|
||||||
|`smart help `|Y |`This help`
|
|`smart help `|Y |`This help`
|
||||||
|`smart list `|Y |`List ISO 7816 history`
|
|`smart list `|Y |`List ISO 7816 history`
|
||||||
|`smart info `|N |`Tag information`
|
|`smart info `|N |`Tag information`
|
||||||
|
|`smart relay `|N |`Turn pm3 into pcsc reader and relay to host OS via vpcd`
|
||||||
|`smart reader `|N |`Act like an IS07816 reader`
|
|`smart reader `|N |`Act like an IS07816 reader`
|
||||||
|`smart raw `|N |`Send raw hex data to tag`
|
|`smart raw `|N |`Send raw hex data to tag`
|
||||||
|`smart upgrade `|Y |`Upgrade sim module firmware`
|
|`smart upgrade `|Y |`Upgrade sim module firmware`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue