Merge pull request #1578 from merlokk/cip_files

Cipurse create files
This commit is contained in:
Oleg Moiseenko 2022-02-02 18:34:58 +02:00 committed by GitHub
commit cbfa764c99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 260 additions and 56 deletions

View file

@ -330,7 +330,7 @@ void CIPURSEPrintInfoFile(uint8_t *data, size_t len) {
CIPURSEPrintManufacturerInfo(data[8]);
}
static void CIPURSEPrintFileDescriptor(uint8_t desc) {
void CIPURSEPrintFileDescriptor(uint8_t desc) {
if (desc == 0x01)
PrintAndLogEx(INFO, "Binary file");
else if (desc == 0x11)

View file

@ -61,5 +61,6 @@ bool CIPURSEChannelAuthenticate(uint8_t keyindex, uint8_t *key, bool verbose);
void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp);
void CIPURSEPrintFileAttr(uint8_t *attr, size_t len);
void CIPURSEPrintFileDescriptor(uint8_t desc);
#endif /* __CIPURSECORE_H__ */

View file

@ -82,6 +82,28 @@ static uint16_t defaultFileId = 0x2ff7;
static int CmdHelp(const char *Cmd);
static int SelectAndPrintInfoFile(void) {
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
int res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000)
return PM3_EAPDU_FAIL;
res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000)
return PM3_EAPDU_FAIL;
if (len > 0) {
PrintAndLogEx(INFO, "Info file ( " _GREEN_("ok") " )");
PrintAndLogEx(INFO, "[%zu]: %s", len, sprint_hex(buf, len));
CIPURSEPrintInfoFile(buf, len);
PrintAndLogEx(INFO, "");
}
return PM3_SUCCESS;
}
static int CmdHFCipurseInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse info",
@ -107,10 +129,14 @@ static int CmdHFCipurseInfo(const char *Cmd) {
uint16_t sw = 0;
bool mfExist = false;
bool infoPrinted = false;
int res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res == PM3_SUCCESS && sw == 0x9000) {
mfExist = true;
PrintAndLogEx(INFO, _CYAN_("MasterFile") " exist and can be selected.");
res = SelectAndPrintInfoFile();
infoPrinted = (res == PM3_SUCCESS);
}
for (int i = 0; i < ARRAYLEN(PxSE_AID_LIST); i++) {
@ -122,6 +148,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
PrintAndLogEx(INFO, "PxSE data:");
TLVPrintFromBuffer(buf, len);
}
PrintAndLogEx(INFO, "");
}
}
@ -130,6 +157,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
DropField();
return res;
}
PrintAndLogEx(INFO, "Application `AF F1` selected " _GREEN_("successfully"));
if (sw != 0x9000) {
if (sw == 0x0000) {
@ -147,30 +175,21 @@ static int CmdHFCipurseInfo(const char *Cmd) {
PrintAndLogEx(INFO, "Cipurse card ( " _GREEN_("ok") " )");
res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
DropField();
return PM3_SUCCESS;
}
res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
DropField();
return PM3_SUCCESS;
}
if (len > 0) {
PrintAndLogEx(INFO, "Info file ( " _GREEN_("ok") " )");
PrintAndLogEx(INFO, "[%zu]: %s", len, sprint_hex(buf, len));
CIPURSEPrintInfoFile(buf, len);
if (!infoPrinted) {
res = SelectAndPrintInfoFile();
if (res != PM3_SUCCESS) {
DropField();
return PM3_SUCCESS;
}
}
DropField();
return PM3_SUCCESS;
}
static int CLIParseCommandParameters(CLIParserContext *ctx, size_t keyid, size_t aidid, size_t fidid, size_t sreqid, size_t srespid,
uint8_t *key, uint8_t *aid, size_t *aidlen, bool *useaid, uint16_t *fid, bool *usefid, CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
static int CLIParseCommandParametersEx(CLIParserContext *ctx, size_t keyid, size_t aidid, size_t fidid, size_t chfidid, size_t sreqid, size_t srespid,
uint8_t *key, uint8_t *aid, size_t *aidlen, bool *useaid, uint16_t *fid, bool *usefid, uint16_t *chfid, bool *usechfid,
CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
uint8_t hdata[250] = {0};
int hdatalen = sizeof(hdata);
if (keyid) {
@ -219,7 +238,7 @@ static int CLIParseCommandParameters(CLIParserContext *ctx, size_t keyid, size_t
return PM3_EINVARG;
}
*fid = defaultFileId;
*fid = 0;
if (hdatalen) {
*fid = (hdata[0] << 8) + hdata[1];
if (usefid)
@ -227,6 +246,24 @@ static int CLIParseCommandParameters(CLIParserContext *ctx, size_t keyid, size_t
}
}
if (usechfid)
*usechfid = false;
if (chfidid && chfid) {
hdatalen = sizeof(hdata);
CLIGetHexWithReturn(ctx, chfidid, hdata, &hdatalen);
if (hdatalen && hdatalen != 2) {
PrintAndLogEx(ERR, _RED_("ERROR:") " child file id length must be 2 bytes only");
return PM3_EINVARG;
}
*chfid = defaultFileId;
if (hdatalen) {
*chfid = (hdata[0] << 8) + hdata[1];
if (usechfid)
*usechfid = true;
}
}
if (sreqid && srespid && sreq && sresp) {
*sreq = CPSMACed;
*sresp = CPSMACed;
@ -275,9 +312,19 @@ static int CLIParseCommandParameters(CLIParserContext *ctx, size_t keyid, size_t
return PM3_SUCCESS;
}
static int SelectCommand(bool selectDefaultFile, bool useAID, uint8_t *aid, size_t aidLen, bool useFID, uint16_t fileId, bool verbose,
static int CLIParseCommandParameters(CLIParserContext *ctx, size_t keyid, size_t aidid, size_t fidid, size_t sreqid, size_t srespid,
uint8_t *key, uint8_t *aid, size_t *aidlen, bool *useaid, uint16_t *fid, bool *usefid,
CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
return CLIParseCommandParametersEx(ctx, keyid, aidid, fidid, 0, sreqid, srespid,
key, aid, aidlen, useaid, fid, usefid, NULL, NULL, sreq, sresp);
}
static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, size_t aidLen, bool useFID, uint16_t fileId,
bool selChildFile, uint16_t childFileId, bool verbose,
uint8_t *buf, size_t bufSize, size_t *len, uint16_t *sw) {
int res = 0;
if (verbose && selChildFile)
PrintAndLogEx(INFO, "Select top level application/file");
if (useAID && aidLen > 0) {
res = CIPURSESelectAID(true, true, aid, aidLen, buf, bufSize, len, sw);
if (res != 0 || *sw != 0x9000) {
@ -316,9 +363,27 @@ static int SelectCommand(bool selectDefaultFile, bool useAID, uint8_t *aid, size
PrintAndLogEx(INFO, "Cipurse select default application " _GREEN_("OK"));
}
if (selChildFile) {
if (verbose)
PrintAndLogEx(INFO, "Select child file");
res = CIPURSESelectFileEx(false, true, childFileId, buf, bufSize, len, sw);
if (res != 0 || *sw != 0x9000) {
if (verbose)
PrintAndLogEx(ERR, "Select child file 0x%04x " _RED_("error") ". Card returns 0x%04x", childFileId, *sw);
return PM3_ESOFT;
}
if (verbose)
PrintAndLogEx(INFO, "Select child file " _CYAN_("0x%04x ") _GREEN_("OK"), childFileId);
}
return PM3_SUCCESS;
}
static int SelectCommand(bool selectDefaultFile, bool useAID, uint8_t *aid, size_t aidLen, bool useFID, uint16_t fileId, bool verbose,
uint8_t *buf, size_t bufSize, size_t *len, uint16_t *sw) {
return SelectCommandEx(selectDefaultFile, useAID, aid, aidLen, useFID, fileId, false, 0, verbose, buf, bufSize, len, sw);
}
static int CmdHFCipurseSelect(const char *Cmd) {
CLIParserContext *ctx;
@ -335,8 +400,9 @@ static int CmdHFCipurseSelect(const char *Cmd) {
arg_lit0("v", "verbose", "show technical data"),
arg_lit0("t", "tlv", "TLV decode returned data"),
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID)"),
arg_str0(NULL, "fid", "<hex 2 bytes>", "file ID (FID)"),
arg_str0(NULL, "fid", "<hex 2 bytes>", "top level file (or application) ID (FID)"),
arg_lit0(NULL, "mfd", "select masterfile by empty id"),
arg_str0(NULL, "chfid", "<hex 2 bytes>", "child file ID (EF under application/master file)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -348,9 +414,11 @@ static int CmdHFCipurseSelect(const char *Cmd) {
uint8_t aid[16] = {0};
size_t aidLen = 0;
bool useAID = false;
uint16_t fileId = defaultFileId;
uint16_t fileId = 0;
bool useFID = false;
int res = CLIParseCommandParameters(ctx, 0, 4, 5, 0, 0, NULL, aid, &aidLen, &useAID, &fileId, &useFID, NULL, NULL);
uint16_t childFileId = defaultFileId;
bool useChildFID = false;
int res = CLIParseCommandParametersEx(ctx, 0, 4, 5, 7, 0, 0, NULL, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, NULL, NULL);
if (res || (useAID && useFID)) {
CLIParserFree(ctx);
return PM3_EINVARG;
@ -365,7 +433,7 @@ static int CmdHFCipurseSelect(const char *Cmd) {
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, true, buf, sizeof(buf), &len, &sw);
res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
DropField();
return PM3_ESOFT;
@ -397,7 +465,7 @@ static int CmdHFCipurseAuth(const char *Cmd) {
arg_lit0("a", "apdu", "show APDU requests and responses"),
arg_lit0("v", "verbose", "show technical data"),
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID)"),
arg_str0(NULL, "fid", "<hex 2 bytes>", "file ID (FID)"),
arg_str0(NULL, "fid", "<hex 2 bytes>", "top file/application ID (FID)"),
arg_lit0(NULL, "mfd", "select masterfile by empty id"),
arg_int0("n", NULL, "<dec>", "key ID"),
arg_str0("k", "key", "<hex>", "Auth key"),
@ -887,7 +955,8 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
"Create application/file/key by provide appropriate DGI. If no key is supplied, default key of 737373...7373 will be used",
"hf cipurse create -d 9200123F00200008000062098407A0000005070100 -> create PTSE file with FID 0x2000 and space for 8 AIDs\n"
"hf cipurse create -d 92002438613F010A050200004040FF021009021009621084054144204631D407A0000005070100A00F28"
"73737373737373737373737373737373015FD67B000102030405060708090A0B0C0D0E0F01C6A13B -> create default file with FID 3F01 and 2 keys\n");
"73737373737373737373737373737373015FD67B000102030405060708090A0B0C0D0E0F01C6A13B -> create default file with FID 3F01 and 2 keys\n"
"hf cipurse create --aid 4144204631 -d 92010C010001020030020000FFFFFF -> create 0x0102 binary data EF under application 4144204631\n");
void *argtable[] = {
arg_param_begin,
@ -895,11 +964,16 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
arg_lit0("v", "verbose", "show technical data"),
arg_int0("n", NULL, "<dec>", "key ID"),
arg_str0("k", "key", "<hex>", "Auth key"),
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID)"),
arg_str0(NULL, "fid", "<hex 2 bytes>", "file ID (FID)"),
arg_lit0(NULL, "mfd", "select masterfile by empty id"),
arg_str0("d", "data", "<hex>", "data with DGI for create"),
arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
arg_lit0(NULL, "no-auth", "execute without authentication"),
arg_lit0(NULL, "commit", "commit "),
arg_lit0(NULL, "commit", "need commit after create"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -912,38 +986,65 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
CipurseChannelSecurityLevel sresp = CPSMACed;
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
uint8_t aid[16] = {0};
size_t aidLen = 0;
bool useAID = false;
uint16_t fileId = defaultFileId;
bool useFID = false;
int res = CLIParseCommandParameters(ctx, 4, 0, 0, 6, 7, key, NULL, NULL, NULL, &fileId, &useFID, &sreq, &sresp);
int res = CLIParseCommandParameters(ctx, 4, 5, 6, 9, 10, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
if (res) {
CLIParserFree(ctx);
return PM3_EINVARG;
}
bool selmfd = arg_get_lit(ctx, 7);
uint8_t hdata[250] = {0};
int hdatalen = sizeof(hdata);
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
CLIGetHexWithReturn(ctx, 8, hdata, &hdatalen);
if (hdatalen < 4 || hdatalen > 200) {
PrintAndLogEx(ERR, _RED_("ERROR:") " data length must be 4-200 bytes only");
CLIParserFree(ctx);
return PM3_EINVARG;
}
bool noauth = arg_get_lit(ctx, 8);
bool needCommit = arg_get_lit(ctx, 9);
bool noauth = arg_get_lit(ctx, 11);
bool needCommit = arg_get_lit(ctx, 12);
CLIParserFree(ctx);
SetAPDULogging(APDULogging);
if (verbose && hdatalen > 3) {
if (hdata[0] == 0x92 && hdata[1] == 0x00)
PrintAndLogEx(INFO, "DGI 9200 - ADF file attributes");
if (hdata[0] == 0x92 && hdata[1] == 0x01) {
PrintAndLogEx(INFO, "DGI 9201 - EF file attributes");
PrintAndLogEx(INFO, "File type:");
CIPURSEPrintFileDescriptor(hdata[3]);
}
if (hdata[0] == 0xa0 && hdata[1] == 0x0f)
PrintAndLogEx(INFO, "DGI a00f - All key values");
}
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField();
return PM3_ESOFT;
if (useAID || useFID || selmfd) {
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
DropField();
return PM3_ESOFT;
}
} else {
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField();
return PM3_ESOFT;
}
if (verbose)
PrintAndLogEx(INFO, "Cipurse masterfile " _GREEN_("selected"));
}
if (verbose) {
@ -981,6 +1082,9 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
res = CIPURSECommitTransaction(&sw);
if (res != 0 || sw != 0x9000)
PrintAndLogEx(WARNING, "Commit " _YELLOW_("ERROR") ". Card returns 0x%04x", sw);
if (verbose)
PrintAndLogEx(INFO, "Commit " _GREEN_("OK"));
}
DropField();
@ -991,9 +1095,10 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse delete",
"Delete file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
"hf cipurse delete --fid 2ff7 -> Authenticate with keyID 1, delete file with id 2ff7\n"
"hf cipurse delete --fid 2ff7 -> Authenticate with keyID 1, delete file with id 2ff7 at top level\n"
"hf cipurse delete -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and delete file\n"
"hf cipurse delete --aid --no-auth -> delete PTSE file with AID A0000005070100 without authentication\n");
"hf cipurse delete --aid A0000005070100 --no-auth -> delete PTSE file with AID A0000005070100 without authentication\n"
"hf cipurse delete --aid 4144204631 --chfid 0102 -> delete EF with FID 0x0102 under default application\n");
void *argtable[] = {
arg_param_begin,
@ -1001,8 +1106,9 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
arg_lit0("v", "verbose", "show technical data"),
arg_int0("n", NULL, "<dec>", "key ID"),
arg_str0("k", "key", "<hex>", "Auth key"),
arg_str0(NULL, "fid", "<hex>", "file ID for delete"),
arg_str0(NULL, "fid", "<hex>", "file/application ID under MF for delete"),
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID) for delete"),
arg_str0(NULL, "chfid", "<hex 2 bytes>", "child file ID (EF under application/master file)"),
arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
arg_lit0(NULL, "no-auth", "execute without authentication"),
@ -1024,36 +1130,30 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
bool useAID = false;
uint16_t fileId = defaultFileId;
bool useFID = false;
int res = CLIParseCommandParameters(ctx, 4, 6, 5, 7, 8, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
uint16_t childFileId = defaultFileId;
bool useChildFID = false;
int res = CLIParseCommandParametersEx(ctx, 4, 6, 5, 7, 8, 9, key, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, &sreq, &sresp);
// useAID and useFID in the same state
if (res || !(useAID ^ useFID)) {
CLIParserFree(ctx);
return PM3_EINVARG;
}
bool noauth = arg_get_lit(ctx, 9);
bool needCommit = arg_get_lit(ctx, 10);
bool noauth = arg_get_lit(ctx, 10);
bool needCommit = arg_get_lit(ctx, 11);
CLIParserFree(ctx);
SetAPDULogging(APDULogging);
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField();
return PM3_ESOFT;
}
if (verbose) {
if (useFID)
PrintAndLogEx(INFO, "File id " _CYAN_("%x"), fileId);
else
PrintAndLogEx(INFO, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid, aidLen));
if (useChildFID)
PrintAndLogEx(INFO, "Child file id " _CYAN_("%x"), childFileId);
if (!noauth)
PrintAndLogEx(INFO, "key id " _YELLOW_("%d") " key " _YELLOW_("%s")
, keyId
@ -1061,6 +1161,26 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
);
}
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
if (useChildFID) {
res = SelectCommand(false, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
PrintAndLogEx(ERR, "Top level select " _RED_("error") ". Card returns 0x%04x", sw);
DropField();
return PM3_ESOFT;
}
} else {
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField();
return PM3_ESOFT;
}
}
if (!noauth) {
bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
if (bres == false) {
@ -1074,7 +1194,16 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
}
if (useFID) {
if (useChildFID) {
res = CIPURSEDeleteFile(childFileId, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
PrintAndLogEx(ERR, "Delete child file " _CYAN_("%04x ") _RED_("ERROR") ". Card returns:\n 0x%04x - %s", childFileId, sw,
GetSpecificAPDUCodeDesc(DeleteAPDUCodeDescriptions, ARRAYLEN(DeleteAPDUCodeDescriptions), sw));
DropField();
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), childFileId);
} else if (useFID) {
res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) {
PrintAndLogEx(ERR, "Delete file " _CYAN_("%04x ") _RED_("ERROR") ". Card returns:\n 0x%04x - %s", fileId, sw,
@ -1101,6 +1230,9 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
res = CIPURSECommitTransaction(&sw);
if (res != 0 || sw != 0x9000)
PrintAndLogEx(WARNING, "Commit " _YELLOW_("ERROR") ". Card returns 0x%04x", sw);
if (verbose)
PrintAndLogEx(INFO, "Commit " _GREEN_("OK"));
}
DropField();

View file

@ -9,6 +9,7 @@
- [Source code](#source-code)
- [Communication channel with a card](#communication-channel-with-a-card)
- [Card architecture](#card-architecture)
- [Card structure](#card-structure)
- [How to](#how-to)
- [How to personalize card](#how-to-personalize-card)
@ -42,6 +43,7 @@ After authentication reader can specify the mode for each channel for each comma
Card answers if the mode that sets by the reader matches the mode of the file and the command matches the key via an access list.
## Card architecture
^[Top](#top)
@ -55,6 +57,28 @@ Master file have keys and an access control list that works at the card level.
Each file can only have an access control list that specifies what operation the key can do with this file.
Card have transaction mechanism. Transaction not needs for control structure at application level and to change files without
transaction mechanism. All the rest changes needs to issue COMMIT command (`--commit` key)
## Card structure
^[Top](#top)
- Master file (MF)
- Keys
- Group security levels and access rights
- files under master file (EF). Usually have no access to them.
- PxSE files (directory files)
- Application 1. Have AID (up to 16-bytes) and FID (2-bytes id)
-- Application keys
-- Group security levels and access rights
-- Application files (EF). Have type (1-byte) and FID ((2-bytes id))
- Application 2
- ...
## How to
### How to select application or file
@ -78,6 +102,24 @@ select it with display output in raw and tlv views options
5. select default file (usually it master file)
```hf cipurse select --mfd```
### How to delete application or file
^[Top](#top)
1. delete PTSE by AID
```hf cipurse delete --aid a0000005070100```
2. delete application by AID
```hf cipurse delete --aid 4144204631```
3. delete application/top level file by FID
```hf cipurse delete --fid 2000```
3. delete file by FID from default application `AD F1`
```hf cipurse delete --aid 4144204631 --chfid 0102```
### How to personalize card
^[Top](#top)
@ -108,7 +150,7 @@ This command creates a application with following details:
- App type............... 61
- Max files count........ 10
- Max SFID count......... 5
- Minimum command's group security levels plain/plain/plain/plain (0000)
- Minimum command's group security levels: plain/plain/plain/plain (0000)
- Access rights.......... all two keys can do anything (FFFFFF)
- Key attributes......... 021009
- 2 keys.........
@ -116,3 +158,32 @@ This command creates a application with following details:
- `0001..0e0f` (01/C6A13B)
- Register in the PxSE... A0000005070100
4. Create elementary file(s) (EF) inside the application
```hf cipurse create --aid 4144204631 -d 92010C010001020030020000FFFFFF --commit```
```
- parent application ID.. 4144204631
- file type.............. 0x01 (binary file wo transaction)
- SFID................... 0x00
- FID.................... 0x0102
- File size.............. 0x0030 (48 bytes)
- Number of keys......... 0x02 (as in the parent application)
- Minimum command's group security levels: plain/plain/plain/plain (0000)
- Access rights.......... all two keys can do anything (FFFFFF)
```
5. Save data to elementary file(s) (EF)
```hf cipurse write --fid 0102 -d 010203040506070809```
or if file with transaction mechanism
```hf cipurse write --fid 0102 -d 010203040506070809 --commit```
6. Check file(s) contents (if needs)
```hf cipurse read --fid 0102```