diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 13f64a616..14616e0f0 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -1382,7 +1382,7 @@ int CmdEMVScan(const char *cmd) { uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - PrintAndLog("--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + 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; @@ -1476,6 +1476,89 @@ int CmdEMVTest(const char *cmd) { return ExecuteCryptoTests(true); } +int CmdEMVRoca(const char *cmd) { + + 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; + + // Init TLV tree + const char *alr = "Root terminal TLV tree"; + struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); + + + + int res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); + + // 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) + ); + +// icc_pk->exp, icc_pk->elen +// icc_pk->modulus, icc_pk->mlen + + + PKISetStrictExecution(true); + } + +out: + + // free tlv object + tlvdb_free(tlvRoot); + + if ( channel == ECC_CONTACTLESS) + DropField(); + + + return 0; +} + + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."}, @@ -1490,13 +1573,14 @@ static command_t CommandTable[] = { {"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, {"test", CmdEMVTest, 0, "Crypto logic test."}, /* - {"getrng", CmdEMVGetrng, 0, "get random number from terminal"}, - {"eload", CmdEmvELoad, 0, "load EMV tag into device"}, - {"dump", CmdEmvDump, 0, "dump EMV tag values"}, - {"sim", CmdEmvSim, 0, "simulate EMV tag"}, - {"clone", CmdEmvClone, 0, "clone an EMV tag"}, + {"getrng", CmdEMVGetrng, 0, "get random number from terminal"}, + {"eload", CmdEmvELoad, 0, "load EMV tag into device"}, + {"dump", CmdEmvDump, 0, "dump EMV tag values"}, + {"sim", CmdEmvSim, 0, "simulate EMV tag"}, + {"clone", CmdEmvClone, 0, "clone an EMV tag"}, */ - {"list", CmdEMVList, 0, "[Deprecated] List ISO7816 history"}, + {"list", CmdEMVList, 0, "[Deprecated] List ISO7816 history"}, + {"roca", CmdEMVRoca, 0, "Extract public keys and run ROCA test"}, {NULL, NULL, 0, NULL} }; diff --git a/client/emv/cmdemv.h b/client/emv/cmdemv.h index b4397fd15..0b0419b07 100644 --- a/client/emv/cmdemv.h +++ b/client/emv/cmdemv.h @@ -34,5 +34,6 @@ 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 CmdEMVRoca(const char *Cmd); #endif diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 0c3bb7626..b67e7ac76 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -519,7 +519,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); @@ -900,7 +900,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], @@ -923,10 +923,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], diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index 1117c7f78..829107126 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -102,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