mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
commit
c9b45ab4bd
8 changed files with 375 additions and 13 deletions
|
@ -155,6 +155,7 @@ CMDSRCS = crapto1/crapto1.c \
|
||||||
emv/test/dda_test.c\
|
emv/test/dda_test.c\
|
||||||
emv/test/cda_test.c\
|
emv/test/cda_test.c\
|
||||||
emv/cmdemv.c \
|
emv/cmdemv.c \
|
||||||
|
emv/emv_roca.c \
|
||||||
mifare4.c \
|
mifare4.c \
|
||||||
cmdanalyse.c \
|
cmdanalyse.c \
|
||||||
cmdhf.c \
|
cmdhf.c \
|
||||||
|
|
|
@ -722,6 +722,7 @@ int CmdEMVExec(const char *cmd) {
|
||||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||||
if (arg_get_lit(11))
|
if (arg_get_lit(11))
|
||||||
channel = ECC_CONTACT;
|
channel = ECC_CONTACT;
|
||||||
|
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||||
CLIParserFree();
|
CLIParserFree();
|
||||||
|
|
||||||
SetAPDULogging(showAPDU);
|
SetAPDULogging(showAPDU);
|
||||||
|
@ -736,7 +737,7 @@ int CmdEMVExec(const char *cmd) {
|
||||||
// PPSE
|
// PPSE
|
||||||
PrintAndLogEx(NORMAL, "\n* PPSE.");
|
PrintAndLogEx(NORMAL, "\n* PPSE.");
|
||||||
SetAPDULogging(showAPDU);
|
SetAPDULogging(showAPDU);
|
||||||
res = EMVSearchPSE(channel, activateField, true, decodeTLV, tlvSelect);
|
res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect);
|
||||||
|
|
||||||
// check PPSE and select application id
|
// check PPSE and select application id
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
@ -1170,6 +1171,7 @@ int CmdEMVScan(const char *cmd) {
|
||||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||||
if (arg_get_lit(11))
|
if (arg_get_lit(11))
|
||||||
channel = ECC_CONTACT;
|
channel = ECC_CONTACT;
|
||||||
|
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||||
uint8_t relfname[250] ={0};
|
uint8_t relfname[250] ={0};
|
||||||
char *crelfname = (char *)relfname;
|
char *crelfname = (char *)relfname;
|
||||||
int relfnamelen = 0;
|
int relfnamelen = 0;
|
||||||
|
@ -1248,7 +1250,7 @@ int CmdEMVScan(const char *cmd) {
|
||||||
tlvdb_free(fci);
|
tlvdb_free(fci);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = EMVSearchPSE(channel, false, true, decodeTLV, tlvSelect);
|
res = EMVSearchPSE(channel, false, true, psenum, decodeTLV, tlvSelect);
|
||||||
|
|
||||||
// check PPSE and select application id
|
// check PPSE and select application id
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
@ -1464,6 +1466,12 @@ int CmdEMVTest(const char *cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEMVRoca(const char *cmd) {
|
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",
|
CLIParserInit("emv roca",
|
||||||
"Tries to extract public keys and run the ROCA test against them.\n",
|
"Tries to extract public keys and run the ROCA test against them.\n",
|
||||||
|
@ -1481,16 +1489,133 @@ int CmdEMVRoca(const char *cmd) {
|
||||||
if (arg_get_lit(1))
|
if (arg_get_lit(1))
|
||||||
channel = ECC_CONTACT;
|
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
|
// Init TLV tree
|
||||||
const char *alr = "Root terminal TLV tree";
|
const char *alr = "Root terminal TLV tree";
|
||||||
struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
|
struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
|
||||||
|
|
||||||
// select card
|
// EMV SELECT applet
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen));
|
||||||
size_t len = 0;
|
res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||||
uint16_t sw = 0;
|
|
||||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1: 2;
|
if (res) {
|
||||||
int res = EMVSelectPSE(channel, true, true, psenum, buf, sizeof(buf), &len, &sw);
|
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
|
// getting certificates
|
||||||
if (tlvdb_get(tlvRoot, 0x90, NULL)) {
|
if (tlvdb_get(tlvRoot, 0x90, NULL)) {
|
||||||
|
@ -1530,9 +1655,17 @@ int CmdEMVRoca(const char *cmd) {
|
||||||
sprint_hex(icc_pk->serial, 3)
|
sprint_hex(icc_pk->serial, 3)
|
||||||
);
|
);
|
||||||
|
|
||||||
// icc_pk->exp, icc_pk->elen
|
PrintAndLogEx(INFO, "ICC pk modulus: %s", sprint_hex_inrow(icc_pk->modulus, icc_pk->mlen));
|
||||||
// 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);
|
PKISetStrictExecution(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "cmdmain.h"
|
#include "cmdmain.h"
|
||||||
#include "emvcore.h"
|
#include "emvcore.h"
|
||||||
#include "apduinfo.h"
|
#include "apduinfo.h"
|
||||||
|
#include "emv_roca.h"
|
||||||
|
|
||||||
int CmdEMV(const char *Cmd);
|
int CmdEMV(const char *Cmd);
|
||||||
|
|
||||||
|
|
185
client/emv/emv_roca.c
Normal file
185
client/emv/emv_roca.c
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/* 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"
|
||||||
|
|
||||||
|
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[%d] %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;
|
||||||
|
}
|
38
client/emv/emv_roca.h
Normal file
38
client/emv/emv_roca.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/* 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 <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "mbedtls/bignum.h"
|
||||||
|
#include "util.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
|
||||||
|
|
|
@ -332,14 +332,14 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
||||||
return res;
|
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};
|
uint8_t data[APDU_RES_LEN] = {0};
|
||||||
size_t datalen = 0;
|
size_t datalen = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
// select PPSE
|
// 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){
|
if (!res){
|
||||||
struct tlvdb *t = NULL;
|
struct tlvdb *t = NULL;
|
||||||
|
|
|
@ -79,7 +79,7 @@ extern void SetAPDULogging(bool logging);
|
||||||
extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
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
|
// 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 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 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);
|
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);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "dda_test.h"
|
#include "dda_test.h"
|
||||||
#include "cda_test.h"
|
#include "cda_test.h"
|
||||||
#include "crypto/libpcrypto.h"
|
#include "crypto/libpcrypto.h"
|
||||||
|
#include "emv/emv_roca.h"
|
||||||
|
|
||||||
int ExecuteCryptoTests(bool verbose) {
|
int ExecuteCryptoTests(bool verbose) {
|
||||||
int res;
|
int res;
|
||||||
|
@ -90,6 +91,9 @@ int ExecuteCryptoTests(bool verbose) {
|
||||||
res = exec_crypto_test(verbose);
|
res = exec_crypto_test(verbose);
|
||||||
if (res) TestFail = true;
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = roca_self_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
PrintAndLog("\n--------------------------");
|
PrintAndLog("\n--------------------------");
|
||||||
if (TestFail)
|
if (TestFail)
|
||||||
PrintAndLog("Test(s) [ERROR].");
|
PrintAndLog("Test(s) [ERROR].");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue