mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-14 01:03:01 -07:00
transactions MSD and M/Chip, qVSDC works
This commit is contained in:
parent
2db66b01da
commit
10d4f82338
4 changed files with 226 additions and 19 deletions
|
@ -283,6 +283,10 @@ int UsageCmdHFEMVExec(void) {
|
||||||
PrintAndLog(" -a : show APDU reqests and responses\n");
|
PrintAndLog(" -a : show APDU reqests and responses\n");
|
||||||
PrintAndLog(" -t : TLV decode results\n");
|
PrintAndLog(" -t : TLV decode results\n");
|
||||||
PrintAndLog(" -f : force search AID. Search AID instead of execute PPSE.\n");
|
PrintAndLog(" -f : force search AID. Search AID instead of execute PPSE.\n");
|
||||||
|
PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
|
||||||
|
PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
|
||||||
|
PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n");
|
||||||
|
PrintAndLog("By default : transaction type - MSD.\n");
|
||||||
PrintAndLog("Samples:");
|
PrintAndLog("Samples:");
|
||||||
PrintAndLog(" hf emv pse -s -> select card");
|
PrintAndLog(" hf emv pse -s -> select card");
|
||||||
PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU");
|
PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU");
|
||||||
|
@ -296,6 +300,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
bool showAPDU = false;
|
bool showAPDU = false;
|
||||||
bool decodeTLV = false;
|
bool decodeTLV = false;
|
||||||
bool forceSearch = false;
|
bool forceSearch = false;
|
||||||
|
enum TransactionType TrType = TT_MSD;
|
||||||
|
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -335,6 +340,18 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
case 'F':
|
case 'F':
|
||||||
forceSearch = true;
|
forceSearch = true;
|
||||||
break;
|
break;
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
TrType = TT_VSDC;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
case 'V':
|
||||||
|
TrType = TT_QVSDCMCHIP;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
TrType = TT_CDA;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
|
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -405,9 +422,24 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
PrintAndLog("\n* Init transaction parameters.");
|
PrintAndLog("\n* Init transaction parameters.");
|
||||||
|
|
||||||
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
||||||
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
switch(TrType) {
|
||||||
// TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
case TT_MSD:
|
||||||
// TLV_ADD(0x9F66, "\x8e\x00\x00\x00"); // CDA
|
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
||||||
|
break;
|
||||||
|
// not standart for contactless. just for test.
|
||||||
|
case TT_VSDC:
|
||||||
|
TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
|
||||||
|
break;
|
||||||
|
case TT_QVSDCMCHIP:
|
||||||
|
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
||||||
|
break;
|
||||||
|
case TT_CDA:
|
||||||
|
TLV_ADD(0x9F66, "\x86\x80\x00\x00"); // CDA
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
||||||
|
break;
|
||||||
|
}
|
||||||
//9F02:(Amount, Authorised (Numeric)) len:6
|
//9F02:(Amount, Authorised (Numeric)) len:6
|
||||||
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
|
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
|
||||||
//9F1A:(Terminal Country Code) len:2
|
//9F1A:(Terminal Country Code) len:2
|
||||||
|
@ -444,6 +476,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
PrintAndLog("\n* GPO.");
|
PrintAndLog("\n* GPO.");
|
||||||
res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
res = EMVGPO(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);
|
free(pdol_data_tlv);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
|
@ -544,13 +577,27 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// transaction check
|
// get AIP
|
||||||
const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);
|
const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);
|
||||||
uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
|
uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
|
||||||
PrintAndLog("* * AIP=%x", AIP);
|
PrintAndLog("* * AIP=%04x", AIP);
|
||||||
|
|
||||||
|
// SDA
|
||||||
|
if (AIP & 0x0040) {
|
||||||
|
PrintAndLog("\n* SDA");
|
||||||
|
trSDA(AID, AIDlen, tlvRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DDA
|
||||||
|
if (AIP & 0x0020) {
|
||||||
|
PrintAndLog("\n* DDA");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction check
|
||||||
|
|
||||||
// qVSDC
|
// qVSDC
|
||||||
{
|
if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){
|
||||||
// 9F26: Application Cryptogram
|
// 9F26: Application Cryptogram
|
||||||
const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
|
const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
|
||||||
if (AC) {
|
if (AC) {
|
||||||
|
@ -587,19 +634,88 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Mastercard M/CHIP
|
// Mastercard M/CHIP
|
||||||
{
|
if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)){
|
||||||
const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL);
|
const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL);
|
||||||
if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag
|
if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag
|
||||||
|
PrintAndLog("\n--> Mastercard M/Chip transaction.");
|
||||||
|
|
||||||
|
PrintAndLog("* * Generate challenge");
|
||||||
|
res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||||
|
if (res) {
|
||||||
|
PrintAndLog("ERROR GetChallenge. APDU error %4x", sw);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
if (len < 4) {
|
||||||
|
PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICC Dynamic Number
|
||||||
|
struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf);
|
||||||
|
tlvdb_add(tlvRoot, ICCDynN);
|
||||||
|
if (decodeTLV){
|
||||||
|
PrintAndLog("\n* * ICC Dynamic Number:");
|
||||||
|
TLVPrintFromTLV(ICCDynN);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("* * Calc CDOL1");
|
||||||
|
struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||||
|
if (!cdol_data_tlv){
|
||||||
|
PrintAndLog("ERROR: can't create CDOL1 TLV.");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
|
||||||
|
|
||||||
|
PrintAndLog("* * AC1");
|
||||||
|
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
|
||||||
|
res = EMVAC(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);
|
||||||
|
|
||||||
|
free(cdol_data_tlv);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decodeTLV)
|
||||||
|
TLVPrintFromBuffer(buf, len);
|
||||||
|
|
||||||
|
PrintAndLog("* M/Chip transaction result:");
|
||||||
|
// 9F27: Cryptogram Information Data (CID)
|
||||||
|
const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL);
|
||||||
|
if (CID) {
|
||||||
|
emv_tag_dump(CID, stdout, 0);
|
||||||
|
PrintAndLog("------------------------------");
|
||||||
|
if (CID->len > 0) {
|
||||||
|
switch(CID->value[0] & EMVAC_AC_MASK){
|
||||||
|
case EMVAC_AAC:
|
||||||
|
PrintAndLog("Transaction DECLINED.");
|
||||||
|
break;
|
||||||
|
case EMVAC_TC:
|
||||||
|
PrintAndLog("Transaction approved OFFLINE.");
|
||||||
|
break;
|
||||||
|
case EMVAC_ARQC:
|
||||||
|
PrintAndLog("Transaction approved ONLINE.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PrintAndLog("ERROR: CID transaction code error %2x", CID->value[0] & EMVAC_AC_MASK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLog("ERROR: Wrong CID length %d", CID->len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLog("ERROR: CID(9F27) not found.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSD
|
// MSD
|
||||||
if (AIP & 0x8000) {
|
if (AIP & 0x8000 && TrType == TT_MSD) {
|
||||||
PrintAndLog("\n--> MSD transaction.");
|
PrintAndLog("\n--> MSD transaction.");
|
||||||
|
|
||||||
|
|
||||||
PrintAndLog("* MSD dCVV path. Check dCVV");
|
PrintAndLog("* MSD dCVV path. Check dCVV");
|
||||||
|
|
||||||
const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
|
const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
|
||||||
|
@ -624,7 +740,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
if (!UDOL)
|
if (!UDOL)
|
||||||
PrintAndLog("Use default UDOL.");
|
PrintAndLog("Use default UDOL.");
|
||||||
|
|
||||||
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - fake tag!
|
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||||
if (!udol_data_tlv){
|
if (!udol_data_tlv){
|
||||||
PrintAndLog("ERROR: can't create UDOL TLV.");
|
PrintAndLog("ERROR: can't create UDOL TLV.");
|
||||||
return 4;
|
return 4;
|
||||||
|
@ -651,9 +767,6 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// additional contacless EMV commands (fDDA, external authenticate)
|
|
||||||
|
|
||||||
|
|
||||||
// DropField
|
// DropField
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ enum emv_tag_t {
|
||||||
EMV_TAG_NUMERIC,
|
EMV_TAG_NUMERIC,
|
||||||
EMV_TAG_YYMMDD,
|
EMV_TAG_YYMMDD,
|
||||||
EMV_TAG_CVR,
|
EMV_TAG_CVR,
|
||||||
|
EMV_TAG_CID,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct emv_tag {
|
struct emv_tag {
|
||||||
|
@ -59,7 +60,7 @@ static const struct emv_tag_bit EMV_AIP[] = {
|
||||||
{ EMV_BIT(1, 4), "Terminal risk management is to be performed" },
|
{ EMV_BIT(1, 4), "Terminal risk management is to be performed" },
|
||||||
{ EMV_BIT(1, 3), "Issuer authentication is supported" },
|
{ EMV_BIT(1, 3), "Issuer authentication is supported" },
|
||||||
{ EMV_BIT(1, 2), "Reserved for use by the EMV Contactless Specifications" },
|
{ EMV_BIT(1, 2), "Reserved for use by the EMV Contactless Specifications" },
|
||||||
{ EMV_BIT(1, 1), "CDA supported" },
|
{ EMV_BIT(1, 1), "CDA supported (Combined Dynamic Data Authentication / Application Cryptogram Generation)" },
|
||||||
{ EMV_BIT(2, 8), "MSD is supported (Magnetic Stripe Data)" },
|
{ EMV_BIT(2, 8), "MSD is supported (Magnetic Stripe Data)" },
|
||||||
{ EMV_BIT(2, 7), "Reserved for use by the EMV Contactless Specifications" },
|
{ EMV_BIT(2, 7), "Reserved for use by the EMV Contactless Specifications" },
|
||||||
{ EMV_BIT(2, 6), "Reserved for use by the EMV Contactless Specifications" },
|
{ EMV_BIT(2, 6), "Reserved for use by the EMV Contactless Specifications" },
|
||||||
|
@ -233,7 +234,7 @@ static const struct emv_tag emv_tags[] = {
|
||||||
{ 0x9f1f, "Track 1 Discretionary Data", EMV_TAG_STRING },
|
{ 0x9f1f, "Track 1 Discretionary Data", EMV_TAG_STRING },
|
||||||
{ 0x9f21, "Transaction Time" },
|
{ 0x9f21, "Transaction Time" },
|
||||||
{ 0x9f26, "Application Cryptogram" },
|
{ 0x9f26, "Application Cryptogram" },
|
||||||
{ 0x9f27, "Cryptogram Information Data" },
|
{ 0x9f27, "Cryptogram Information Data", EMV_TAG_CID },
|
||||||
{ 0x9f2a, "Kernel Identifier" },
|
{ 0x9f2a, "Kernel Identifier" },
|
||||||
{ 0x9f2d, "ICC PIN Encipherment Public Key Certificate" },
|
{ 0x9f2d, "ICC PIN Encipherment Public Key Certificate" },
|
||||||
{ 0x9f2e, "ICC PIN Encipherment Public Key Exponent" },
|
{ 0x9f2e, "ICC PIN Encipherment Public Key Exponent" },
|
||||||
|
@ -471,6 +472,50 @@ static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, F
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EMV Book 3
|
||||||
|
static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||||
|
if (!tlv || tlv->len < 1) {
|
||||||
|
PRINT_INDENT(level);
|
||||||
|
fprintf(f, "\tINVALID!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_INDENT(level);
|
||||||
|
if ((tlv->value[0] & 0xC0) == 0x00) fprintf(f, "\tAC1: AAC (Transaction declined)\n");
|
||||||
|
if ((tlv->value[0] & 0xC0) == 0x40) fprintf(f, "\tAC1: TC (Transaction approved)\n");
|
||||||
|
if ((tlv->value[0] & 0xC0) == 0x80) fprintf(f, "\tAC1: ARQC (Online authorisation requested)\n");
|
||||||
|
if ((tlv->value[0] & 0xC0) == 0xC0) fprintf(f, "\tAC1: RFU\n");
|
||||||
|
|
||||||
|
if ((tlv->value[0] & 0x08) != 0x00) {
|
||||||
|
PRINT_INDENT(level);
|
||||||
|
fprintf(f, "\tAdvice required!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tlv->value[0] & 0x07) != 0x00) {
|
||||||
|
PRINT_INDENT(level);
|
||||||
|
fprintf(f, "\tReason/advice/referral code: ");
|
||||||
|
switch((tlv->value[0] & 0x07)) {
|
||||||
|
case 0:
|
||||||
|
fprintf(f, "No information given\n");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fprintf(f, "Service not allowed\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fprintf(f, "PIN Try Limit exceeded\n");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
fprintf(f, "Issuer authentication failed\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(f, "\tRFU: %2x\n", (tlv->value[0] & 0x07));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||||
{
|
{
|
||||||
uint32_t X, Y;
|
uint32_t X, Y;
|
||||||
|
@ -628,6 +673,10 @@ bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level)
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
emv_tag_dump_cvr(tlv, tag, f, level);
|
emv_tag_dump_cvr(tlv, tag, f, level);
|
||||||
break;
|
break;
|
||||||
|
case EMV_TAG_CID:
|
||||||
|
fprintf(f, "\n");
|
||||||
|
emv_tag_dump_cid(tlv, tag, f, level);
|
||||||
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -242,13 +242,13 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Re
|
||||||
// 6 byes + data = INS + CLA + P1 + P2 + Lc + <data = Nc> + Le
|
// 6 byes + data = INS + CLA + P1 + P2 + Lc + <data = Nc> + Le
|
||||||
int res = ExchangeAPDU14a(data, 6 + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
int res = ExchangeAPDU14a(data, 6 + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||||
|
|
||||||
if (APDULogging)
|
|
||||||
PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen));
|
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (APDULogging)
|
||||||
|
PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen));
|
||||||
|
|
||||||
*ResultLen -= 2;
|
*ResultLen -= 2;
|
||||||
isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1];
|
isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1];
|
||||||
if (sw)
|
if (sw)
|
||||||
|
@ -467,3 +467,29 @@ int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen
|
||||||
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||||
return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Authentication
|
||||||
|
int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) {
|
||||||
|
if (AIDlen < 5)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Get public key index (0x8F)
|
||||||
|
//int PubKeyIndx = 0;
|
||||||
|
|
||||||
|
// Get public key from key storage
|
||||||
|
// GetPublicKey(AID(0..5), PubKeyIndx)
|
||||||
|
|
||||||
|
// Processing of Issuer Public Key Certificate (0x90)
|
||||||
|
//Certificate =
|
||||||
|
|
||||||
|
// check issuer public key certificate
|
||||||
|
|
||||||
|
// Verification of Signed Static Application Data (SSAD) (0x93)
|
||||||
|
|
||||||
|
// get 9F4A Static Data Authentication Tag List
|
||||||
|
|
||||||
|
// set Data Auth Code (9F45) from SSAD
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,20 @@
|
||||||
#define APDU_RES_LEN 260
|
#define APDU_RES_LEN 260
|
||||||
#define APDU_AID_LEN 50
|
#define APDU_AID_LEN 50
|
||||||
|
|
||||||
|
// AC
|
||||||
|
# define EMVAC_AC_MASK 0xC0
|
||||||
|
# define EMVAC_AAC 0x00
|
||||||
|
# define EMVAC_TC 0x40
|
||||||
|
# define EMVAC_ARQC 0x80
|
||||||
|
# define EMVAC_CDAREQ 0x10
|
||||||
|
|
||||||
|
enum TransactionType {
|
||||||
|
TT_MSD,
|
||||||
|
TT_VSDC, // not standart for contactless!!!!
|
||||||
|
TT_QVSDCMCHIP,
|
||||||
|
TT_CDA,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t CLA;
|
uint8_t CLA;
|
||||||
uint8_t INS;
|
uint8_t INS;
|
||||||
|
@ -69,8 +83,13 @@ extern int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen)
|
||||||
// Get Processing Options
|
// Get Processing Options
|
||||||
extern int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
extern int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
|
// AC
|
||||||
|
extern int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
|
extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
// Mastercard
|
// Mastercard
|
||||||
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
|
// Auth
|
||||||
|
extern int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue