mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-22 14:13:42 -07:00
half of SDA works
This commit is contained in:
parent
58bf374646
commit
8d9526f375
6 changed files with 136 additions and 30 deletions
7
client/emv/capk.txt
Normal file
7
client/emv/capk.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
a0:00:00:00:03 01 091231 rsa 03 c6:96:03:42:13:d7:d8:54:69:84:57:9d:1d:0f:0e:a5:19:cf:f8:de:ff:c4:29:35:4c:f3:a8:71:a6:f7:18:3f:12:28:da:5c:74:70:c0:55:38:71:00:cb:93:5a:71:2c:4e:28:64:df:5d:64:ba:93:fe:7e:63:e7:1f:25:b1:e5:f5:29:85:75:eb:e1:c6:3a:a6:17:70:69:17:91:1d:c2:a7:5a:c2:8b:25:1c:7e:f4:0f:23:65:91:24:90:b9:39:bc:a2:12:4a:30:a2:8f:54:40:2c:34:ae:ca:33:1a:b6:7e:1e:79:b2:85:dd:57:71:b5:d9:ff:79:ea:63:0b:75 sha1 d3:4a:6a:77:60:11:c7:e7:ce:3a:ec:5f:03:ad:2f:8c:fc:55:03:cc
|
||||||
|
a0:00:00:00:03 07 171231 rsa 03 a8:9f:25:a5:6f:a6:da:25:8c:8c:a8:b4:04:27:d9:27:b4:a1:eb:4d:7e:a3:26:bb:b1:2f:97:de:d7:0a:e5:e4:48:0f:c9:c5:e8:a9:72:17:71:10:a1:cc:31:8d:06:d2:f8:f5:c4:84:4a:c5:fa:79:a4:dc:47:0b:b1:1e:d6:35:69:9c:17:08:1b:90:f1:b9:84:f1:2e:92:c1:c5:29:27:6d:8a:f8:ec:7f:28:49:20:97:d8:cd:5b:ec:ea:16:fe:40:88:f6:cf:ab:4a:1b:42:32:8a:1b:99:6f:92:78:b0:b7:e3:31:1c:a5:ef:85:6c:2f:88:84:74:b8:36:12:a8:2e:4e:00:d0:cd:40:69:a6:78:31:40:43:3d:50:72:5f sha1 b4:bc:56:cc:4e:88:32:49:32:cb:c6:43:d6:89:8f:6f:e5:93:b1:72
|
||||||
|
a0:00:00:00:03 08 221231 rsa 03 d9:fd:6e:d7:5d:51:d0:e3:06:64:bd:15:70:23:ea:a1:ff:a8:71:e4:da:65:67:2b:86:3d:25:5e:81:e1:37:a5:1d:e4:f7:2b:cc:9e:44:ac:e1:21:27:f8:7e:26:3d:3a:f9:dd:9c:f3:5c:a4:a7:b0:1e:90:70:00:ba:85:d2:49:54:c2:fc:a3:07:48:25:dd:d4:c0:c8:f1:86:cb:02:0f:68:3e:02:f2:de:ad:39:69:13:3f:06:f7:84:51:66:ac:eb:57:ca:0f:c2:60:34:45:46:98:11:d2:93:bf:ef:ba:fa:b5:76:31:b3:dd:91:e7:96:bf:85:0a:25:01:2f:1a:e3:8f:05:aa:5c:4d:6d:03:b1:dc:2e:56:86:12:78:59:38:bb:c9:b3:cd:3a:91:0c:1d:a5:5a:5a:92:18:ac:e0:f7:a2:12:87:75:26:82:f1:58:32:a6:78:d6:e1:ed:0b sha1 20:d2:13:12:69:55:de:20:5a:dc:2f:d2:82:2b:d2:2d:e2:1c:f9:a8
|
||||||
|
a0:00:00:00:03 09 221231 rsa 03 9d:91:22:48:de:0a:4e:39:c1:a7:dd:e3:f6:d2:58:89:92:c1:a4:09:5a:fb:d1:82:4d:1b:a7:48:47:f2:bc:49:26:d2:ef:d9:04:b4:b5:49:54:cd:18:9a:54:c5:d1:17:96:54:f8:f9:b0:d2:ab:5f:03:57:eb:64:2f:ed:a9:5d:39:12:c6:57:69:45:fa:b8:97:e7:06:2c:aa:44:a4:aa:06:b8:fe:6e:3d:ba:18:af:6a:e3:73:8e:30:42:9e:e9:be:03:42:7c:9d:64:f6:95:fa:8c:ab:4b:fe:37:68:53:ea:34:ad:1d:76:bf:ca:d1:59:08:c0:77:ff:e6:dc:55:21:ec:ef:5d:27:8a:96:e2:6f:57:35:9f:fa:ed:a1:94:34:b9:37:f1:ad:99:9d:c5:c4:1e:b1:19:35:b4:4c:18:10:0e:85:7f:43:1a:4a:5a:6b:b6:51:14:f1:74:c2:d7:b5:9f:df:23:7d:6b:b1:dd:09:16:e6:44:d7:09:de:d5:64:81:47:7c:75:d9:5c:dd:68:25:46:15:f7:74:0e:c0:7f:33:0a:c5:d6:7b:cd:75:bf:23:d2:8a:14:08:26:c0:26:db:de:97:1a:37:cd:3e:f9:b8:df:64:4a:c3:85:01:05:01:ef:c6:50:9d:7a:41 sha1 1f:f8:0a:40:17:3f:52:d7:d2:7e:0f:26:a1:46:a1:c8:cc:b2:90:46
|
||||||
|
a0:00:00:00:03 95 000000 rsa 03 be:9e:1f:a5:e9:a8:03:85:29:99:c4:ab:43:2d:b2:86:00:dc:d9:da:b7:6d:fa:aa:47:35:5a:0f:e3:7b:15:08:ac:6b:f3:88:60:d3:c6:c2:e5:b1:2a:3c:aa:f2:a7:00:5a:72:41:eb:aa:77:71:11:2c:74:cf:9a:06:34:65:2f:bc:a0:e5:98:0c:54:a6:47:61:ea:10:1a:11:4e:0f:0b:55:72:ad:d5:7d:01:0b:7c:9c:88:7e:10:4c:a4:ee:12:72:da:66:d9:97:b9:a9:0b:5a:6d:62:4a:b6:c5:7e:73:c8:f9:19:00:0e:b5:f6:84:89:8e:f8:c3:db:ef:b3:30:c6:26:60:be:d8:8e:a7:8e:90:9a:ff:05:f6:da:62:7b sha1 ee:15:11:ce:c7:10:20:a9:b9:04:43:b3:7b:1d:5f:6e:70:30:30:f6
|
||||||
|
a0:00:00:00:03 92 000000 rsa 03 99:6a:f5:6f:56:91:87:d0:92:93:c1:48:10:45:0e:d8:ee:33:57:39:7b:18:a2:45:8e:fa:a9:2d:a3:b6:df:65:14:ec:06:01:95:31:8f:d4:3b:e9:b8:f0:cc:66:9e:3f:84:40:57:cb:dd:f8:bd:a1:91:bb:64:47:3b:c8:dc:9a:73:0d:b8:f6:b4:ed:e3:92:41:86:ff:d9:b8:c7:73:57:89:c2:3a:36:ba:0b:8a:f6:53:72:eb:57:ea:5d:89:e7:d1:4e:9c:7b:6b:55:74:60:f1:08:85:da:16:ac:92:3f:15:af:37:58:f0:f0:3e:bd:3c:5c:2c:94:9c:ba:30:6d:b4:4e:6a:2c:07:6c:5f:67:e2:81:d7:ef:56:78:5d:c4:d7:59:45:e4:91:f0:19:18:80:0a:9e:2d:c6:6f:60:08:05:66:ce:0d:af:8d:17:ea:d4:6a:d8:e3:0a:24:7c:9f sha1 42:9c:95:4a:38:59:ce:f9:12:95:f6:63:c9:63:e5:82:ed:6e:b2:53
|
||||||
|
a0:00:00:00:03 94 000000 rsa 03 ac:d2:b1:23:02:ee:64:4f:3f:83:5a:bd:1f:c7:a6:f6:2c:ce:48:ff:ec:62:2a:a8:ef:06:2b:ef:6f:b8:ba:8b:c6:8b:bf:6a:b5:87:0e:ed:57:9b:c3:97:3e:12:13:03:d3:48:41:a7:96:d6:dc:bc:41:db:f9:e5:2c:46:09:79:5c:0c:cf:7e:e8:6f:a1:d5:cb:04:10:71:ed:2c:51:d2:20:2f:63:f1:15:6c:58:a9:2d:38:bc:60:bd:f4:24:e1:77:6e:2b:c9:64:80:78:a0:3b:36:fb:55:43:75:fc:53:d5:7c:73:f5:16:0e:a5:9f:3a:fc:53:98:ec:7b:67:75:8d:65:c9:bf:f7:82:8b:6b:82:d4:be:12:4a:41:6a:b7:30:19:14:31:1e:a4:62:c1:9f:77:1f:31:b3:b5:73:36:00:0d:ff:73:2d:3b:83:de:07:05:2d:73:03:54:d2:97:be:c7:28:71:dc:cf:0e:19:3f:17:1a:ba:27:ee:46:4c:6a:97:69:09:43:d5:9b:da:bb:2a:27:eb:71:ce:eb:da:fa:11:76:04:64:78:fd:62:fe:c4:52:d5:ca:39:32:96:53:0a:a3:f4:19:27:ad:fe:43:4a:2d:f2:ae:30:54:f8:84:06:57:a2:6e:0f:c6:17 sha1 c4:a3:c4:3c:cf:87:32:7d:13:6b:80:41:60:e4:7d:43:b6:0e:6e:0f
|
|
@ -592,7 +592,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
// DDA
|
// DDA
|
||||||
if (AIP & 0x0020) {
|
if (AIP & 0x0020) {
|
||||||
PrintAndLog("\n* DDA");
|
PrintAndLog("\n* DDA");
|
||||||
|
trDDA(AID, AIDlen, tlvRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transaction check
|
// transaction check
|
||||||
|
|
|
@ -399,7 +399,7 @@ static struct emv_pk *emv_pk_get_ca_pk_from_file(const char *fname,
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!feof(f)) {
|
while (!feof(f)) {
|
||||||
char buf[BUFSIZ];
|
char buf[2048];
|
||||||
if (fgets(buf, sizeof(buf), f) == NULL)
|
if (fgets(buf, sizeof(buf), f) == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -472,7 +472,7 @@ struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
|
||||||
{
|
{
|
||||||
struct emv_pk *pk = NULL;
|
struct emv_pk *pk = NULL;
|
||||||
|
|
||||||
if (!pk) {
|
/* if (!pk) {
|
||||||
char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
|
char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
|
||||||
if (fname) {
|
if (fname) {
|
||||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||||
|
@ -487,14 +487,9 @@ struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
|
||||||
free(fname);
|
free(fname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (!pk) {
|
if (!pk) {
|
||||||
const char *fname = "capk.txt"; //openemv_config_get_str("capk.file", NULL);
|
const char *fname = "emv/capk.txt";
|
||||||
if (!fname) {
|
|
||||||
fprintf(stderr, "No CA PK file specified!\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||||
}
|
}
|
||||||
if (!pk)
|
if (!pk)
|
||||||
|
|
|
@ -177,6 +177,7 @@ static const struct emv_tag emv_tags[] = {
|
||||||
{ 0x01 , "", EMV_TAG_STRING }, // string for headers
|
{ 0x01 , "", EMV_TAG_STRING }, // string for headers
|
||||||
{ 0x02 , "Raw data", }, // data
|
{ 0x02 , "Raw data", }, // data
|
||||||
{ 0x20 , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
|
{ 0x20 , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
|
||||||
|
{ 0x21 , "SDA data" }, // not standard! data for offline authentication from read records command
|
||||||
|
|
||||||
// EMV
|
// EMV
|
||||||
{ 0x41 , "Country code and national data" },
|
{ 0x41 , "Country code and national data" },
|
||||||
|
|
|
@ -469,27 +469,127 @@ int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authentication
|
// Authentication
|
||||||
|
static 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);
|
||||||
|
|
||||||
|
if (!df_tlv || !caidx_tlv || df_tlv->len < 6 || caidx_tlv->len != 1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
PrintAndLog("CA public key index 0x%0x", caidx_tlv->value[0]);
|
||||||
|
return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]);
|
||||||
|
}
|
||||||
|
|
||||||
int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) {
|
int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) {
|
||||||
if (AIDlen < 5)
|
if (AIDlen < 5)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
struct emv_pk *pk = get_ca_pk(tlv);
|
||||||
|
if (!pk) {
|
||||||
|
PrintAndLog("ERROR: Key not found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Get public key index (0x8F)
|
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
|
||||||
//int PubKeyIndx = 0;
|
if (!issuer_pk) {
|
||||||
|
PrintAndLog("ERROR: Issuer certificate found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("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],
|
||||||
|
issuer_pk->rid[3],
|
||||||
|
issuer_pk->rid[4],
|
||||||
|
issuer_pk->index,
|
||||||
|
issuer_pk->serial[0],
|
||||||
|
issuer_pk->serial[1],
|
||||||
|
issuer_pk->serial[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
||||||
|
if (!sda_tlv || sda_tlv->len < 1) {
|
||||||
|
PrintAndLog("ERROR: Can't find dynamic authentication data. Exit.");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
// Get public key from key storage
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
// GetPublicKey(AID(0..5), PubKeyIndx)
|
if (dac_db) {
|
||||||
|
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||||
// Processing of Issuer Public Key Certificate (0x90)
|
PrintAndLog("SDA verified OK (%02hhx:%02hhx)!\n", dac_tlv->value[0], dac_tlv->value[1]);
|
||||||
//Certificate =
|
tlvdb_add(tlv, dac_db);
|
||||||
|
} else {
|
||||||
// check issuer public key certificate
|
PrintAndLog("ERROR: SSAD verify error");
|
||||||
|
}
|
||||||
// Verification of Signed Static Application Data (SSAD) (0x93)
|
|
||||||
|
|
||||||
// get 9F4A Static Data Authentication Tag List
|
|
||||||
|
|
||||||
// set Data Auth Code (9F45) from SSAD
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int trDDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) {
|
||||||
|
if (AIDlen < 5)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
struct emv_pk *pk = get_ca_pk(tlv);
|
||||||
|
if (!pk) {
|
||||||
|
PrintAndLog("ERROR: Key not found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
||||||
|
if (!sda_tlv || sda_tlv->len < 1) {
|
||||||
|
PrintAndLog("ERROR: Can't find dynamic authentication data. Exit.");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
|
||||||
|
if (issuer_pk)
|
||||||
|
printf("Issuer PK recovered! RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||||
|
issuer_pk->rid[0],
|
||||||
|
issuer_pk->rid[1],
|
||||||
|
issuer_pk->rid[2],
|
||||||
|
issuer_pk->rid[3],
|
||||||
|
issuer_pk->rid[4],
|
||||||
|
issuer_pk->index,
|
||||||
|
issuer_pk->serial[0],
|
||||||
|
issuer_pk->serial[1],
|
||||||
|
issuer_pk->serial[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
|
||||||
|
if (icc_pk)
|
||||||
|
printf("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],
|
||||||
|
icc_pk->rid[3],
|
||||||
|
icc_pk->rid[4],
|
||||||
|
icc_pk->index,
|
||||||
|
icc_pk->serial[0],
|
||||||
|
icc_pk->serial[1],
|
||||||
|
icc_pk->serial[2]
|
||||||
|
);
|
||||||
|
struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv);
|
||||||
|
if (icc_pe_pk)
|
||||||
|
printf("ICC PE PK recovered! RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||||
|
icc_pe_pk->rid[0],
|
||||||
|
icc_pe_pk->rid[1],
|
||||||
|
icc_pe_pk->rid[2],
|
||||||
|
icc_pe_pk->rid[3],
|
||||||
|
icc_pe_pk->rid[4],
|
||||||
|
icc_pe_pk->index,
|
||||||
|
icc_pe_pk->serial[0],
|
||||||
|
icc_pe_pk->serial[1],
|
||||||
|
icc_pe_pk->serial[2]
|
||||||
|
);
|
||||||
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
|
if (dac_db) {
|
||||||
|
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||||
|
printf("SDA verified OK (%02hhx:%02hhx)!\n", dac_tlv->value[0], dac_tlv->value[1]);
|
||||||
|
tlvdb_add(tlv, dac_db);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -20,11 +20,13 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "cmdhf14a.h"
|
#include "cmdhf14a.h"
|
||||||
#include "emv/apduinfo.h"
|
#include "apduinfo.h"
|
||||||
#include "emv/tlv.h"
|
#include "tlv.h"
|
||||||
#include "emv/dol.h"
|
#include "dol.h"
|
||||||
#include "emv/dump.h"
|
#include "dump.h"
|
||||||
#include "emv/emv_tags.h"
|
#include "emv_tags.h"
|
||||||
|
#include "emv_pk.h"
|
||||||
|
#include "emv_pki.h"
|
||||||
|
|
||||||
#define APDU_RES_LEN 260
|
#define APDU_RES_LEN 260
|
||||||
#define APDU_AID_LEN 50
|
#define APDU_AID_LEN 50
|
||||||
|
@ -90,6 +92,7 @@ extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CD
|
||||||
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
|
// Auth
|
||||||
extern int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv);
|
extern int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv);
|
||||||
|
extern int trDDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue