1
0
mirror of https://github.com/Proxmark/proxmark3.git synced 2025-03-12 04:35:36 -07:00

Add ROCA vulnerability test (RRG repository PR 76 by @merlokk) ()

This commit is contained in:
pwpiwi 2019-01-21 19:26:54 +01:00 committed by GitHub
parent d3c606574f
commit 1511ea28a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 491 additions and 49 deletions

@ -156,6 +156,7 @@ CMDSRCS = $(SRC_SMARTCARD) \
emv/test/dda_test.c\
emv/test/cda_test.c\
emv/cmdemv.c\
emv/emv_roca.c \
cmdhf.c \
cmdhflist.c \
cmdhf14a.c \
@ -250,7 +251,7 @@ endif
BINS = proxmark3 flasher fpga_compress
WINBINS = $(patsubst %, %.exe, $(BINS))
CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h
CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h lualibs/usb_cmd.lua
# need to assign dependancies to build these first...
all: lua_build jansson_build mbedtls_build cbor_build $(BINS)
@ -295,7 +296,7 @@ lua_build:
jansson_build:
@echo Compiling jansson
cd ./jansson && make all
cd $(JANSSONLIBPATH) && make all
mbedtls_build:
@echo Compiling mbedtls

@ -8,14 +8,20 @@
// EMV commands
//-----------------------------------------------------------------------------
#include <ctype.h>
#include "mifare.h"
#include "cmdemv.h"
#include <ctype.h>
#include "proxmark3.h"
#include "cmdparser.h"
#include "mifare.h"
#include "emvjson.h"
#include "emv_pki.h"
#include "emvcore.h"
#include "test/cryptotest.h"
#include "cliparser/cliparser.h"
#include <jansson.h>
#include "jansson.h"
#include "emv_roca.h"
#define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) )
void ParamLoadDefaults(struct tlvdb *tlvRoot) {
@ -323,10 +329,8 @@ int CmdEMVReadRecord(const char *cmd) {
arg_lit0("kK", "keep", "keep field ON for next command"),
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
#ifdef WITH_SMARTCARD
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
#endif
arg_strx1(NULL, NULL, "<SFI 1byte HEX><SFIrec 1byte HEX>", NULL),
arg_strx1(NULL, NULL, "<SFI 1byte HEX><SFIrecord 1byte HEX>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
@ -544,8 +548,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
int datalen = 0;
CLIParserInit("emv intauth",
"Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.",
"Usage:\n\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n"
"Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\n"
"Needs a EMV applet to be selected and GPO to be executed.",
"Usage:\n"
"\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n"
"\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n"
"\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV");
@ -720,7 +727,8 @@ int CmdEMVExec(const char *cmd) {
CLIParserInit("emv exec",
"Executes EMV contactless transaction",
"Usage:\n\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n"
"Usage:\n"
"\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n"
"\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n");
void* argtable[] = {
@ -735,9 +743,7 @@ int CmdEMVExec(const char *cmd) {
arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)."),
arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standart behavior."),
arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."),
#ifdef WITH_SMARTCARD
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
#endif
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
@ -762,6 +768,7 @@ int CmdEMVExec(const char *cmd) {
if (arg_get_lit(11))
channel = ECC_CONTACT;
#endif
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
CLIParserFree();
SetAPDULogging(showAPDU);
@ -776,7 +783,7 @@ int CmdEMVExec(const char *cmd) {
// PPSE
PrintAndLogEx(NORMAL, "\n* PPSE.");
SetAPDULogging(showAPDU);
res = EMVSearchPSE(channel, activateField, true, decodeTLV, tlvSelect);
res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect);
// check PPSE and select application id
if (!res) {
@ -1212,12 +1219,14 @@ int CmdEMVScan(const char *cmd) {
char *crelfname = (char *)relfname;
int relfnamelen = 0;
#ifdef WITH_SMARTCARD
if (arg_get_lit(11))
if (arg_get_lit(11)) {
channel = ECC_CONTACT;
}
CLIGetStrWithReturn(12, relfname, &relfnamelen);
#else
CLIGetStrWithReturn(11, relfname, &relfnamelen);
#endif
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
CLIParserFree();
SetAPDULogging(showAPDU);
@ -1292,7 +1301,7 @@ int CmdEMVScan(const char *cmd) {
tlvdb_free(fci);
}
res = EMVSearchPSE(channel, false, true, decodeTLV, tlvSelect);
res = EMVSearchPSE(channel, false, true, psenum, decodeTLV, tlvSelect);
// check PPSE and select application id
if (!res) {
@ -1502,7 +1511,225 @@ int CmdEMVTest(const char *cmd) {
return ExecuteCryptoTests(true);
}
int CmdEMVRoca(const char *cmd) {
uint8_t AID[APDU_AID_LEN] = {0};
size_t AIDlen = 0;
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
int res;
CLIParserInit("emv roca",
"Tries to extract public keys and run the ROCA test against them.\n",
"Usage:\n"
"\temv roca -w -> select CONTACT card and run test\n\temv roca -> select CONTACTLESS card and run test\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(1))
channel = ECC_CONTACT;
// select card
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
SetAPDULogging(false);
// init applets list tree
const char *al = "Applets list";
struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
// EMV PPSE
PrintAndLogEx(NORMAL, "--> PPSE.");
res = EMVSearchPSE(channel, false, true, psenum, false, tlvSelect);
// check PPSE and select application id
if (!res) {
TLVPrintAIDlistFromSelectTLV(tlvSelect);
} else {
// EMV SEARCH with AID list
PrintAndLogEx(NORMAL, "--> AID search.");
if (EMVSearch(channel, false, true, false, tlvSelect)) {
PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
tlvdb_free(tlvSelect);
DropField();
return 3;
}
// check search and select application id
TLVPrintAIDlistFromSelectTLV(tlvSelect);
}
// EMV SELECT application
SetAPDULogging(false);
EMVSelectApplication(tlvSelect, AID, &AIDlen);
tlvdb_free(tlvSelect);
if (!AIDlen) {
PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit...");
DropField();
return 4;
}
// Init TLV tree
const char *alr = "Root terminal TLV tree";
struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
// EMV SELECT applet
PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen));
res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot);
if (res) {
PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res);
tlvdb_free(tlvRoot);
DropField();
return 5;
}
PrintAndLog("\n* Init transaction parameters.");
InitTransactionParameters(tlvRoot, true, TT_QVSDCMCHIP, false);
PrintAndLogEx(NORMAL, "-->Calc PDOL.");
struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
if (!pdol_data_tlv){
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
tlvdb_free(tlvRoot);
DropField();
return 6;
}
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(ERR, "Can't create PDOL data.");
tlvdb_free(tlvRoot);
DropField();
return 6;
}
PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
PrintAndLogEx(INFO, "-->GPO.");
res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
free(pdol_data_tlv_data);
free(pdol_data_tlv);
if (res) {
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
tlvdb_free(tlvRoot);
DropField();
return 7;
}
ProcessGPOResponseFormat1(tlvRoot, buf, len, false);
PrintAndLogEx(INFO, "-->Read records from AFL.");
const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL);
while(AFL && AFL->len) {
if (AFL->len % 4) {
PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len);
break;
}
for (int i = 0; i < AFL->len / 4; i++) {
uint8_t SFI = AFL->value[i * 4 + 0] >> 3;
uint8_t SFIstart = AFL->value[i * 4 + 1];
uint8_t SFIend = AFL->value[i * 4 + 2];
uint8_t SFIoffline = AFL->value[i * 4 + 3];
PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline);
if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
PrintAndLogEx(ERR, "SFI ERROR! Skipped...");
continue;
}
for(int n = SFIstart; n <= SFIend; n++) {
PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n);
res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot);
if (res) {
PrintAndLogEx(ERR, "SFI[%02x]. APDU error %4x", SFI, sw);
continue;
}
}
}
break;
}
// getting certificates
if (tlvdb_get(tlvRoot, 0x90, NULL)) {
PrintAndLogEx(INFO, "-->Recovering certificates.");
PKISetStrictExecution(false);
struct emv_pk *pk = get_ca_pk(tlvRoot);
if (!pk) {
PrintAndLogEx(ERR, "ERROR: Key not found. Exit.");
goto out;
}
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlvRoot);
if (!issuer_pk) {
emv_pk_free(pk);
PrintAndLogEx(WARNING, "WARNING: Issuer certificate not found. Exit.");
goto out;
}
PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %s IDX %02hhx CSN %s",
sprint_hex(issuer_pk->rid, 5),
issuer_pk->index,
sprint_hex(issuer_pk->serial, 3)
);
struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL);
if (!icc_pk) {
emv_pk_free(pk);
emv_pk_free(issuer_pk);
PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit.");
goto out;
}
PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %s IDX %02hhx CSN %s\n",
sprint_hex(icc_pk->rid, 5),
icc_pk->index,
sprint_hex(icc_pk->serial, 3)
);
PrintAndLogEx(INFO, "ICC pk modulus: %s", sprint_hex_inrow(icc_pk->modulus, icc_pk->mlen));
// icc_pk->exp, icc_pk->elen
// icc_pk->modulus, icc_pk->mlen
if (icc_pk->elen > 0 && icc_pk->mlen > 0) {
if (emv_rocacheck(icc_pk->modulus, icc_pk->mlen, true)) {
PrintAndLogEx(INFO, "ICC pk is a subject to ROCA vulnerability, insecure..");
} else {
PrintAndLogEx(INFO, "ICC pk is OK(");
}
}
PKISetStrictExecution(true);
}
out:
// free tlv object
tlvdb_free(tlvRoot);
if ( channel == ECC_CONTACTLESS)
DropField();
return 0;
}
int CmdHelp(const char *Cmd);
static command_t CommandTable[] = {
{"help", CmdHelp, 1, "This help"},
{"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."},
@ -1516,6 +1743,7 @@ static command_t CommandTable[] = {
{"intauth", CmdEMVInternalAuthenticate, 0, "Internal authentication."},
{"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."},
{"test", CmdEMVTest, 0, "Crypto logic test."},
{"roca", CmdEMVRoca, 0, "Extract public keys and run ROCA test"},
{NULL, NULL, 0, NULL}
};

@ -11,28 +11,6 @@
#ifndef CMDEMV_H__
#define CMDEMV_H__
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <ctype.h>
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "util.h"
#include "util_posix.h"
#include "cmdmain.h"
#include "emvcore.h"
#include "apduinfo.h"
int CmdEMV(const char *Cmd);
extern int CmdEMVSelect(const char *cmd);
extern int CmdEMVSearch(const char *cmd);
extern int CmdEMVPPSE(const char *cmd);
extern int CmdEMVExec(const char *cmd);
extern int CmdEMVGetrng(const char *Cmd);
extern int CmdEMVList(const char *Cmd);
extern int CmdEMV(const char *Cmd);
#endif

193
client/emv/emv_roca.c Normal file

@ -0,0 +1,193 @@
/* roca.c - ROCA (CVE-2017-15361) fingerprint checker.
* Written by Rob Stradling (based on https://github.com/crocs-muni/roca/blob/master/roca/detect.py)
* Copyright (C) 2017-2018 Sectigo Limited
* modified 2018 iceman (dropped openssl bignum, now use mbedtls lib)
* modified 2018 merlok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//-----------------------------------------------------------------------------
// EMV roca commands
//-----------------------------------------------------------------------------
#include "emv_roca.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "ui.h"
#include "mbedtls/bignum.h"
static uint8_t g_primes[ROCA_PRINTS_LENGTH] = {
11, 13, 17, 19, 37, 53, 61, 71, 73, 79, 97, 103, 107, 109, 127, 151, 157
};
mbedtls_mpi g_prints[ROCA_PRINTS_LENGTH];
void rocacheck_init(void) {
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++)
mbedtls_mpi_init(&g_prints[i]);
mbedtls_mpi_read_string(&g_prints[0], 10, "1026");
mbedtls_mpi_read_string(&g_prints[1], 10, "5658");
mbedtls_mpi_read_string(&g_prints[2], 10, "107286");
mbedtls_mpi_read_string(&g_prints[3], 10, "199410");
mbedtls_mpi_read_string(&g_prints[4], 10, "67109890");
mbedtls_mpi_read_string(&g_prints[5], 10, "5310023542746834");
mbedtls_mpi_read_string(&g_prints[6], 10, "1455791217086302986");
mbedtls_mpi_read_string(&g_prints[7], 10, "20052041432995567486");
mbedtls_mpi_read_string(&g_prints[8], 10, "6041388139249378920330");
mbedtls_mpi_read_string(&g_prints[9], 10, "207530445072488465666");
mbedtls_mpi_read_string(&g_prints[10], 10, "79228162521181866724264247298");
mbedtls_mpi_read_string(&g_prints[11], 10, "1760368345969468176824550810518");
mbedtls_mpi_read_string(&g_prints[12], 10, "50079290986288516948354744811034");
mbedtls_mpi_read_string(&g_prints[13], 10, "473022961816146413042658758988474");
mbedtls_mpi_read_string(&g_prints[14], 10, "144390480366845522447407333004847678774");
mbedtls_mpi_read_string(&g_prints[15], 10, "1800793591454480341970779146165214289059119882");
mbedtls_mpi_read_string(&g_prints[16], 10, "126304807362733370595828809000324029340048915994");
}
void rocacheck_cleanup(void) {
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++)
mbedtls_mpi_free(&g_prints[i]);
}
int bitand_is_zero( mbedtls_mpi* a, mbedtls_mpi* b ) {
for (int i = 0; i < mbedtls_mpi_bitlen(a); i++) {
if (mbedtls_mpi_get_bit(a, i) && mbedtls_mpi_get_bit(b, i))
return 0;
}
return 1;
}
mbedtls_mpi_uint mpi_get_uint(const mbedtls_mpi *X) {
if (X->n == 1 && X->s > 0) {
return X->p[0];
}
printf("ZERRRRO!!!\n");
return 0;
}
void print_mpi(const char *msg, int radix, const mbedtls_mpi *X) {
char Xchar[400] = {0};
size_t len = 0;
mbedtls_mpi_write_string(X, radix, Xchar, sizeof(Xchar), &len);
printf("%s[%zd] %s\n", msg, len, Xchar);
}
bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose) {
mbedtls_mpi t_modulus;
mbedtls_mpi_init(&t_modulus);
bool ret = false;
rocacheck_init();
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary(&t_modulus, buf, buflen) );
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++) {
mbedtls_mpi t_temp;
mbedtls_mpi t_prime;
mbedtls_mpi g_one;
mbedtls_mpi_init(&t_temp);
mbedtls_mpi_init(&t_prime);
mbedtls_mpi_init(&g_one);
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string(&g_one, 10, "1") );
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(&t_prime, &t_prime, g_primes[i]) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi(&t_temp, &t_modulus, &t_prime) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(&g_one, mpi_get_uint(&t_temp)) );
if (bitand_is_zero(&g_one, &g_prints[i])) {
if (verbose)
PrintAndLogEx(FAILED, "No fingerprint found.\n");
goto cleanup;
}
mbedtls_mpi_free(&g_one);
mbedtls_mpi_free(&t_temp);
mbedtls_mpi_free(&t_prime);
}
ret = true;
if (verbose)
PrintAndLogEx(SUCCESS, "Fingerprint found!\n");
cleanup:
mbedtls_mpi_free(&t_modulus);
rocacheck_cleanup();
return ret;
}
int roca_self_test( int verbose ) {
int ret = 0;
if( verbose != 0 )
printf( "\nROCA check vulnerability tests\n" );
// positive
uint8_t keyp[] = "\x94\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
if( verbose != 0 )
printf( " ROCA positive test: " );
if (emv_rocacheck(keyp, 64, false)) {
if( verbose != 0 )
printf( "passed\n" );
} else {
ret = 1;
if( verbose != 0 )
printf( "failed\n" );
}
// negative
uint8_t keyn[] = "\x84\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
if( verbose != 0 )
printf( " ROCA negative test: " );
if (emv_rocacheck(keyn, 64, false)) {
ret = 1;
if( verbose != 0 )
printf( "failed\n" );
} else {
if( verbose != 0 )
printf( "passed\n" );
}
return ret;
}

36
client/emv/emv_roca.h Normal file

@ -0,0 +1,36 @@
/* roca.c - ROCA (CVE-2017-15361) fingerprint checker.
* Written by Rob Stradling (based on https://github.com/crocs-muni/roca/blob/master/roca/detect.py)
* Copyright (C) 2017-2018 Sectigo Limited
* modified 2018 iceman (dropped openssl bignum, now use mbedtls lib)
* modified 2018 merlok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//-----------------------------------------------------------------------------
// EMV roca commands
//-----------------------------------------------------------------------------
#ifndef EMV_ROCA_H__
#define EMV_ROCA_H__
#include <stddef.h>
#include <stdbool.h>
#define ROCA_PRINTS_LENGTH 17
extern bool emv_rocacheck( const unsigned char *buf, size_t buflen, bool verbose );
extern int roca_self_test( int verbose );
#endif

@ -123,7 +123,7 @@ static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf)
return true;
}
void TLVPrintFromBuffer(uint8_t *data, int datalen) {
bool TLVPrintFromBuffer(uint8_t *data, int datalen) {
struct tlvdb *t = NULL;
t = tlvdb_parse_multi(data, datalen);
if (t) {
@ -131,9 +131,11 @@ void TLVPrintFromBuffer(uint8_t *data, int datalen) {
tlvdb_visit(t, print_cb, NULL, 0);
tlvdb_free(t);
return true;
} else {
PrintAndLogEx(WARNING, "TLV ERROR: Can't parse response as TLV tree.");
}
return false;
}
void TLVPrintFromTLVLev(struct tlvdb *tlv, int level) {
@ -335,14 +337,14 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
return res;
}
int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) {
uint8_t data[APDU_RES_LEN] = {0};
size_t datalen = 0;
uint16_t sw = 0;
int res;
// select PPSE
res = EMVSelectPSE(channel, ActivateField, true, 2, data, sizeof(data), &datalen, &sw);
res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw);
if (!res){
struct tlvdb *t = NULL;
@ -522,7 +524,7 @@ int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8
}
// Authentication
static struct emv_pk *get_ca_pk(struct tlvdb *db) {
struct emv_pk *get_ca_pk(struct tlvdb *db) {
const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL);
const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL);
@ -903,7 +905,7 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) {
PrintAndLog("WARNING: Issuer certificate not found. Exit.");
return 2;
}
PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx",
PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx",
issuer_pk->rid[0],
issuer_pk->rid[1],
issuer_pk->rid[2],
@ -926,10 +928,10 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) {
if (!icc_pk) {
emv_pk_free(pk);
emv_pk_free(issuer_pk);
PrintAndLog("WARNING: ICC certificate not found. Exit.");
PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit.");
return 2;
}
printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
icc_pk->rid[0],
icc_pk->rid[1],
icc_pk->rid[2],

@ -65,7 +65,7 @@ enum CardPSVendor {
};
extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen);
extern void TLVPrintFromBuffer(uint8_t *data, int datalen);
extern bool TLVPrintFromBuffer(uint8_t *data, int datalen);
extern void TLVPrintFromTLV(struct tlvdb *tlv);
extern void TLVPrintFromTLVLev(struct tlvdb *tlv, int level);
extern void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv);
@ -78,9 +78,8 @@ extern void SetAPDULogging(bool logging);
// exchange
extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
// search application
extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv);
extern int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
extern int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
extern int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
@ -103,6 +102,7 @@ extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_
extern int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root);
extern struct emv_pk *get_ca_pk(struct tlvdb *db);
#endif

@ -31,6 +31,7 @@
#include "dda_test.h"
#include "cda_test.h"
#include "crypto/libpcrypto.h"
#include "emv/emv_roca.h"
int ExecuteCryptoTests(bool verbose) {
int res;
@ -90,6 +91,9 @@ int ExecuteCryptoTests(bool verbose) {
res = exec_crypto_test(verbose);
if (res) TestFail = true;
res = roca_self_test(verbose);
if (res) TestFail = true;
PrintAndLog("\n--------------------------");
if (TestFail)
PrintAndLog("Test(s) [ERROR].");