Merge pull request #95 from merlokk/emv_vsdc

Emv vsdc
This commit is contained in:
Oleg Moiseenko 2019-02-19 21:30:30 +02:00 committed by GitHub
commit 9cd0256a81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 127 additions and 16 deletions

View file

@ -1182,17 +1182,17 @@ int CmdEMVExec(const char *cmd) {
PrintAndLogEx(NORMAL, "\n--> VSDC transaction.");
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) {
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.");
dreturn(6);
}
PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol1_data_tlv->len, sprint_hex(cdol1_data_tlv->value, cdol1_data_tlv->len));
PrintAndLogEx(NORMAL, "* * AC1");
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
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);
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);
@ -1201,14 +1201,111 @@ int CmdEMVExec(const char *cmd) {
// process Format1 (0x80) anf print Format2 (0x77)
ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV);
uint8_t CID = 0;
tlvdb_get_uint8(tlvRoot, 0x9f27, &CID);
// AC1 print result
PrintAndLog("");
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)");
if ((CID & EMVAC_AC_MASK) == EMVAC_AC_MASK) PrintAndLogEx(INFO, "AC1 result: RFU");
// decode Issuer Application Data (IAD)
uint8_t CryptoVersion = 0;
const struct tlv *IAD = tlvdb_get(tlvRoot, 0x9f10, NULL);
if (IAD && (IAD->len > 1)) {
PrintAndLogEx(NORMAL, "\n* * Issuer Application Data (IAD):");
uint8_t VDDlen = IAD->value[0]; // Visa discretionary data length
uint8_t IDDlen = 0; // Issuer discretionary data length
PrintAndLogEx(NORMAL, "IAD length: %d", IAD->len);
PrintAndLogEx(NORMAL, "VDDlen: %d", VDDlen);
if (VDDlen < IAD->len - 1)
IDDlen = IAD->value[VDDlen + 1];
PrintAndLogEx(NORMAL, "IDDlen: %d", IDDlen);
uint8_t DerivKeyIndex = IAD->value[1];
CryptoVersion = IAD->value[2];
PrintAndLogEx(NORMAL, "CryptoVersion: %d", CryptoVersion);
PrintAndLogEx(NORMAL, "DerivKeyIndex: %d", DerivKeyIndex);
// Card Verification Results (CVR) decode
if ((VDDlen - 2) > 0) {
uint8_t CVRlen = IAD->value[3];
if (CVRlen == (VDDlen - 2 - 1)) {
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));
}
}
if (IDDlen)
PrintAndLogEx(NORMAL, "IDD: %s", sprint_hex(&IAD->value[VDDlen + 1], IDDlen));
} else {
PrintAndLogEx(NORMAL, "Issuer Application Data (IAD) not found.");
}
PrintAndLogEx(NORMAL, "\n* * Processing online request\n");
PrintAndLogEx(NORMAL, "\n* * Processing online request");
// authorization response code from acquirer
const char HostResponse[] = "00"; // 0x3030
PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse);
tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse);
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) {
PrintAndLogEx(NORMAL, "\n* * Generate ARPC");
// Application Cryptogram (AC)
const struct tlv *AC = tlvdb_get(tlvRoot, 0x9f26, NULL);
if (AC && (AC->len > 0)) {
PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len));
size_t rawARPClen = AC->len;
uint8_t rawARPC[rawARPClen];
memcpy(rawARPC, AC->value, AC->len);
for (int i = 0; (i < HostResponseLen) && (i < rawARPClen); i++)
rawARPC[i] ^= HostResponse[i];
PrintAndLogEx(NORMAL, "raw ARPC: %s", sprint_hex(rawARPC, rawARPClen));
// here must be calculation of ARPC, but we dont know a bank keys.
PrintAndLogEx(NORMAL, "ARPC: n/a");
} else {
PrintAndLogEx(NORMAL, "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.");
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");
if ((CID & EMVAC_AC2_MASK) == EMVAC_TC2) fprintf(f, "\tAC2: TC (Transaction approved)\n");
if ((CID & EMVAC_AC2_MASK) == EMVAC_ARQC2) fprintf(f, "\tAC2: not requested (ARQC)\n");
if ((CID & EMVAC_AC2_MASK) == EMVAC_AC2_MASK) fprintf(f, "\tAC2: RFU\n");
*/
}
}

View file

@ -25,6 +25,10 @@
# define EMVAC_TC 0x40
# define EMVAC_ARQC 0x80
# define EMVAC_CDAREQ 0x10
# define EMVAC_AC2_MASK 0x30
# define EMVAC_AAC2 0x00
# define EMVAC_TC2 0x10
# define EMVAC_ARQC2 0x20
// CID
# define EMVCID_ADVICE 0x08

View file

@ -263,7 +263,6 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField
break;
case ECC_CONTACT:
#ifdef WITH_SMARTCARD
//int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
#else
res = 1;
@ -799,7 +798,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
return 4;
}
PrintAndLogEx(NORMAL, "\n* Calc DDOL");
PrintAndLogEx(NORMAL, "\n* * Calc DDOL");
const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL);
if (!ddol_tlv) {
ddol_tlv = &default_ddol_tlv;
@ -817,7 +816,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
PrintAndLogEx(NORMAL, "DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
PrintAndLogEx(NORMAL, "\n* Internal Authenticate");
PrintAndLogEx(NORMAL, "\n* * Internal Authenticate");
int res = EMVInternalAuthenticate(channel, true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
if (res) {
PrintAndLogEx(WARNING, "Internal Authenticate error(%d): %4x. Exit...", res, sw);
@ -844,7 +843,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
tlvdb_free(t80);
if (decodeTLV){
PrintAndLogEx(NORMAL, "* * Decode response format 1:");
PrintAndLogEx(NORMAL, "* * * Decode response format 1:");
TLVPrintFromTLV(dda_db);
}
}
@ -879,12 +878,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
// 9f4c ICC Dynamic Number
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
if(idn_tlv) {
PrintAndLogEx(NORMAL, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
PrintAndLogEx(NORMAL, "DDA verified OK.");
PrintAndLogEx(INFO, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
PrintAndLogEx(INFO, "DDA verified OK.");
tlvdb_add(tlv, idn_db);
tlvdb_free(idn_db);
} else {
PrintAndLogEx(NORMAL, "\nERROR: DDA verify error");
PrintAndLogEx(ERR, "\nDDA verify error");
tlvdb_free(idn_db);
emv_pk_free(pk);

View file

@ -39,7 +39,7 @@ typedef enum {
enum TransactionType {
TT_MSD,
TT_VSDC, // not standart for contactless!!!!
TT_VSDC, // contact only. not standart for contactless
TT_QVSDCMCHIP,
TT_CDA,
};

View file

@ -469,7 +469,10 @@ const struct tlv *tlvdb_get_inchild(const struct tlvdb *tlvdb, tlv_tag_t tag, co
}
const struct tlv *tlvdb_get_tlv(const struct tlvdb *tlvdb) {
return &tlvdb->tag;
if (tlvdb)
return &tlvdb->tag;
else
return NULL;
}
unsigned char *tlv_encode(const struct tlv *tlv, size_t *len)
@ -546,6 +549,12 @@ struct tlvdb *tlvdb_elm_get_parent(struct tlvdb *tlvdb)
return tlvdb->parent;
}
bool tlvdb_get_uint8(struct tlvdb *tlvRoot, tlv_tag_t tag, uint8_t *value)
{
const struct tlv *tlvelm = tlvdb_get(tlvRoot, tag, NULL);
return tlv_get_uint8(tlvelm, value);
}
bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value)
{
*value = 0;

View file

@ -65,4 +65,6 @@ bool tlv_equal(const struct tlv *a, const struct tlv *b);
bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value);
bool tlv_get_int(const struct tlv *etlv, int *value);
bool tlvdb_get_uint8(struct tlvdb *tlvRoot, tlv_tag_t tag, uint8_t *value);
#endif