From 242979933e3564b8fb3815cfb8208f3409a91b4c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:14:41 +0200 Subject: [PATCH 01/16] print smr and art --- client/src/cipurse/cipursecore.c | 41 ++++++++++++++++++++++++++++++++ client/src/cipurse/cipursecore.h | 3 +++ 2 files changed, 44 insertions(+) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 0a068bd1c..a5609ff02 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -361,6 +361,43 @@ static void CIPURSEPrintKeyAttrib(uint8_t *attr) { PrintAndLogEx(NORMAL, ""); } +const char *CIPURSEGetSMR(uint8_t smr) { + switch (smr) { + case 0x00: return "plain"; + case 0x01: return "mac"; + case 0x02: return "enc"; + default: return "unknown"; + } + return "unknown"; +} + +void CIPURSEPrintSMR(uint8_t *smrrec) { + PrintAndLogEx(INFO, "%s/%s/%s/%s", + CIPURSEGetSMR((smrrec[0] >> 8) & 0x03), + CIPURSEGetSMR(smrrec[0] & 0x03), + CIPURSEGetSMR((smrrec[1] >> 8) & 0x03), + CIPURSEGetSMR(smrrec[1] & 0x03)); +} + +void CIPURSEPrintART(uint8_t *artrec, size_t artlen) { + if (artlen < 1 || artlen > 9) + return; + for (int i = 0; i < artlen; i++) { + if (i == 0) + PrintAndLogEx(INFO, "always: " NOLF); + else + PrintAndLogEx(INFO, "key %d : " NOLF, i); + + for (int n = 0; n < 8; n++) + if ((artrec[i] >> n) && 0x01) + PrintAndLogEx(NORMAL, "%d " NOLF, n + 1); + else + PrintAndLogEx(NORMAL, " " NOLF); + + PrintAndLogEx(NORMAL, ""); + } +} + void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { if (len < 7) { PrintAndLogEx(FAILED, "Attributes length too short"); @@ -406,10 +443,12 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { if (len >= 9) { PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]); + CIPURSEPrintSMR(&attr[7]); } if (len >= 10 + keynum + 1) { PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], keynum + 1)); + CIPURSEPrintART(&attr[9], keynum + 1); } if (len >= 11 + keynum + 1 + keynum * 7) { @@ -449,10 +488,12 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { if (len >= 9) { PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]); + CIPURSEPrintSMR(&attr[7]); } if (len >= 10) { PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], len - 9)); + CIPURSEPrintART(&attr[9], len - 9); if (attr[6] + 1 != len - 9) { PrintAndLogEx(WARNING, "ART length is wrong"); diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index ee002f135..2311c33f8 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -60,6 +60,9 @@ int CIPURSECancelTransaction(uint16_t *sw); bool CIPURSEChannelAuthenticate(uint8_t keyindex, uint8_t *key, bool verbose); void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp); +const char *CIPURSEGetSMR(uint8_t smr); +void CIPURSEPrintSMR(uint8_t *smrrec); +void CIPURSEPrintART(uint8_t *artrec, size_t artlen); void CIPURSEPrintFileAttr(uint8_t *attr, size_t len); void CIPURSEPrintFileDescriptor(uint8_t desc); From 4c97c5478738dba8662870d1a4007eac61754500 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:32:28 +0200 Subject: [PATCH 02/16] read command is ok --- client/src/cmdhfcipurse.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 379b88b1e..4f6cf68f7 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -533,7 +533,8 @@ static int CmdHFCipurseReadFile(const char *Cmd) { CLIParserInit(&ctx, "hf cipurse read", "Read file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", "hf cipurse read --fid 2ff7 -> Authenticate with keyID 1, read file with id 2ff7\n" - "hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n"); + "hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n" + "hf cipurse read --aid 4144204631 --fid 0102 -> read file with id 0102 from application 4144204631\n"); void *argtable[] = { arg_param_begin, @@ -541,6 +542,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { arg_lit0("v", "verbose", "show technical data"), arg_int0("n", NULL, "", "key ID"), arg_str0("k", "key", "", "Auth key"), + arg_str0(NULL, "aid", "", "application ID (AID)"), arg_str0(NULL, "fid", "", "file ID"), arg_int0("o", "offset", "", "offset for reading data from file"), arg_lit0(NULL, "noauth", "read file without authentication"), @@ -559,17 +561,20 @@ static int CmdHFCipurseReadFile(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, 5, 8, 9, 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 || useFID == false) { CLIParserFree(ctx); return PM3_EINVARG; } - size_t offset = arg_get_int_def(ctx, 6, 0); + size_t offset = arg_get_int_def(ctx, 7, 0); - bool noAuth = arg_get_lit(ctx, 7); + bool noAuth = arg_get_lit(ctx, 8); SetAPDULogging(APDULogging); @@ -579,15 +584,17 @@ static int CmdHFCipurseReadFile(const char *Cmd) { uint16_t sw = 0; uint8_t buf[APDU_RES_LEN] = {0}; - res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { - PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw); + PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw); DropField(); return PM3_ESOFT; } - if (verbose) + if (verbose) { + PrintAndLogEx(INFO, "Cipurse select application " _CYAN_("%s") " ( " _GREEN_("ok") " )", sprint_hex_inrow(aid, aidLen)); PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s"), fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); + } if (noAuth == false) { bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); @@ -605,7 +612,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) - PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw); + PrintAndLogEx(ERR, "File select ( " _RED_("error") " ). Card returns 0x%04x", sw); DropField(); return PM3_ESOFT; } @@ -1280,6 +1287,7 @@ static int CmdHFCipurseDefault(const char *Cmd) { memcpy(defaultKey, ckey, CIPURSE_AES_KEY_LENGTH); uint8_t aid[CIPURSE_MAX_AID_LENGTH] = CIPURSE_DEFAULT_AID; memcpy(defaultAID, aid, CIPURSE_MAX_AID_LENGTH); + defaultAIDLength = 5; } defaultKeyId = arg_get_int_def(ctx, 2, defaultKeyId); From 8a63b3356126eee851045506cdd53dec11ddce7b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:39:58 +0200 Subject: [PATCH 03/16] write file ok --- client/src/cmdhfcipurse.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 4f6cf68f7..dbc9c9d72 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -531,7 +531,7 @@ static int CmdHFCipurseAuth(const char *Cmd) { static int CmdHFCipurseReadFile(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf cipurse read", - "Read file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", + "Read file in the application by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", "hf cipurse read --fid 2ff7 -> Authenticate with keyID 1, read file with id 2ff7\n" "hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n" "hf cipurse read --aid 4144204631 --fid 0102 -> read file with id 0102 from application 4144204631\n"); @@ -640,9 +640,10 @@ static int CmdHFCipurseReadFile(const char *Cmd) { static int CmdHFCipurseWriteFile(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf cipurse write", - "Write file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", - "hf cipurse write --fid 2ff7 -> Authenticate with keyID 1, write file with id 2ff7\n" - "hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and write file\n"); + "Write file in the application by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", + "hf cipurse write --fid 2ff7 -d aabb -> Authenticate with keyID 1, write file with id 2ff7\n" + "hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -d aabb -> Authenticate keyID 2 and write file\n" + "hf cipurse write --aid 4144204631 --fid 0102 -d aabb -> write file with id 0102 in the 4144204631 application\n"); void *argtable[] = { arg_param_begin, @@ -650,6 +651,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { arg_lit0("v", "verbose", "show technical data"), arg_int0("n", NULL, "", "key ID"), arg_str0("k", "key", "", "Auth key"), + arg_str0(NULL, "aid", "", "application ID (AID)"), arg_str0(NULL, "fid", "", "file ID"), arg_int0("o", "offset", "", "offset for reading data from file"), arg_lit0(NULL, "noauth", "read file without authentication"), @@ -669,21 +671,24 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { 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, 5, 8, 9, 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 || useFID == false) { CLIParserFree(ctx); return PM3_EINVARG; } - size_t offset = arg_get_int_def(ctx, 6, 0); + size_t offset = arg_get_int_def(ctx, 7, 0); - bool noAuth = arg_get_lit(ctx, 7); + bool noAuth = arg_get_lit(ctx, 8); uint8_t hdata[250] = {0}; int hdatalen = sizeof(hdata); - CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen); + CLIGetHexWithReturn(ctx, 11, hdata, &hdatalen); if (hdatalen == 0) { PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0"); CLIParserFree(ctx); @@ -698,14 +703,15 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { uint16_t sw = 0; uint8_t buf[APDU_RES_LEN] = {0}; - res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { - PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw); + PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw); DropField(); return PM3_ESOFT; } if (verbose) { + PrintAndLogEx(INFO, "Cipurse select application " _CYAN_("%s") " ( " _GREEN_("ok") " )", sprint_hex_inrow(aid, aidLen)); PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s") , fileId , offset From 7622a6011153323ee28b03517af11f18bdca24f0 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:44:47 +0200 Subject: [PATCH 04/16] add doc --- doc/cipurse.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/cipurse.md b/doc/cipurse.md index 4edc7ad58..2c4a83bae 100644 --- a/doc/cipurse.md +++ b/doc/cipurse.md @@ -120,6 +120,35 @@ select it with display output in raw and tlv views options ```hf cipurse delete --aid 4144204631 --chfid 0102``` +### How read file +^[Top](#top) + +with default key and aid +```hf cipurse read --fid 0102``` + +with default key and specified aid +```hf cipurse read --aid a0000005070100``` + +with default key and aid without authentication +```hf cipurse read --fid 0102 --no-auth``` + + +### How write file +^[Top](#top) + +with default key and aid +```hf cipurse read --fid 0102 -d abbbccdd``` + +with default key and specified aid +```hf cipurse read --aid a0000005070100 -d abbbccdd``` + +with default key and aid without authentication +```hf cipurse read --fid 0102 -d abbbccdd --no-auth``` + +with default key and aid, perform commit (works for files with transactions mechanism switched on) +```hf cipurse read --fid 0102 -d abbbccdd --commit``` + + ### How to personalize card ^[Top](#top) From d65956bf137fa3546bf03b2c686906f067375e97 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:50:55 +0200 Subject: [PATCH 05/16] add commit to write --- client/src/cmdhfcipurse.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index dbc9c9d72..ab99e48ad 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -643,7 +643,8 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { "Write file in the application by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", "hf cipurse write --fid 2ff7 -d aabb -> Authenticate with keyID 1, write file with id 2ff7\n" "hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -d aabb -> Authenticate keyID 2 and write file\n" - "hf cipurse write --aid 4144204631 --fid 0102 -d aabb -> write file with id 0102 in the 4144204631 application\n"); + "hf cipurse write --aid 4144204631 --fid 0102 -d aabb -> write file with id 0102 in the 4144204631 application\n" + "hf cipurse write --fid 0102 -d aabb --commit -> write file with id 0102 and perform commit after write\n"); void *argtable[] = { arg_param_begin, @@ -658,6 +659,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), arg_str0(NULL, "sresp", "", "communication PICC-reader security level"), arg_str0("d", "data", "", "hex data to write to new file"), + arg_lit0(NULL, "commit", "need commit after write"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -695,10 +697,12 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { return PM3_EINVARG; } - SetAPDULogging(APDULogging); + bool needCommit = arg_get_lit(ctx, 12); CLIParserFree(ctx); + SetAPDULogging(APDULogging); + size_t len = 0; uint16_t sw = 0; uint8_t buf[APDU_RES_LEN] = {0}; @@ -755,6 +759,16 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " successfully written", fileId); + if (needCommit) { + sw = 0; + 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(); return PM3_SUCCESS; } From 27ef47a5eb7a4445a4a6bdf31d426851b424c3eb Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 20:09:48 +0200 Subject: [PATCH 06/16] fix in the aread --- client/src/cipurse/cipursecore.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index a5609ff02..3ab862051 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -446,20 +446,21 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { CIPURSEPrintSMR(&attr[7]); } - if (len >= 10 + keynum + 1) { + if (len >= 9 + keynum + 1) { PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], keynum + 1)); CIPURSEPrintART(&attr[9], keynum + 1); + PrintAndLogEx(NORMAL, ""); } - if (len >= 11 + keynum + 1 + keynum * 7) { + if (len >= 9 + keynum + 1 + keynum * 7) { for (int i = 0; i < keynum; i++) { - PrintAndLogEx(INFO, "Key %d Attributes... %s", i, sprint_hex(&attr[11 + keynum + 1 + i * 7], 7)); - CIPURSEPrintKeyAttrib(&attr[11 + keynum + 1 + i * 7]); + PrintAndLogEx(INFO, "Key %d Attributes... %s", i + 1, sprint_hex(&attr[9 + keynum + 1 + i * 7], 7)); + CIPURSEPrintKeyAttrib(&attr[9 + keynum + 1 + i * 7]); } } // MF if (attr[1] == 0x00) { - PrintAndLogEx(INFO, "Total memory size... %d", (attr[len - 6] << 16) + (attr[len - 1] << 5) + attr[len - 4]); + PrintAndLogEx(INFO, "Total memory size... %d", (attr[len - 6] << 16) + (attr[len - 5] << 8) + attr[len - 4]); PrintAndLogEx(INFO, "Free memory size.... %d", (attr[len - 3] << 16) + (attr[len - 2] << 8) + attr[len - 1]); } else { From 349c3ed74c4acad89b6a617cfa225c25a595fbb6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 20:19:36 +0200 Subject: [PATCH 07/16] added some MF info --- client/src/cipurse/cipursecore.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 3ab862051..0bd063e9e 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -458,6 +458,15 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { CIPURSEPrintKeyAttrib(&attr[9 + keynum + 1 + i * 7]); } } + // MF + FCP + if (attr[1] == 0x00 && len >= 9 + keynum + 1 + keynum * 7 + 1) { + int xlen = len - (9 + keynum + 1 + keynum * 7) - 6; + if (xlen > 0 && xlen < 200) { + PrintAndLogEx(INFO, "FCP... [%d] %s", xlen, sprint_hex(&attr[9 + keynum + 1 + keynum * 7], xlen)); + TLVPrintFromBuffer(&attr[9 + keynum + 1 + keynum * 7], xlen); + PrintAndLogEx(INFO, ""); + } + } // MF if (attr[1] == 0x00) { PrintAndLogEx(INFO, "Total memory size... %d", (attr[len - 6] << 16) + (attr[len - 5] << 8) + attr[len - 4]); From a93fb00afb30a2e81a278b131cabdeb9f54eac67 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 20:26:37 +0200 Subject: [PATCH 08/16] aread fix --- client/src/cipurse/cipursecore.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 0bd063e9e..a359666bb 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -458,25 +458,23 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { CIPURSEPrintKeyAttrib(&attr[9 + keynum + 1 + i * 7]); } } - // MF + FCP - if (attr[1] == 0x00 && len >= 9 + keynum + 1 + keynum * 7 + 1) { - int xlen = len - (9 + keynum + 1 + keynum * 7) - 6; + // FCP + if (len >= 9 + keynum + 1 + keynum * 7 + 1) { + int xlen = len - (9 + keynum + 1 + keynum * 7); + // for MF only + if (attr[1] == 0x00) + xlen = xlen - 6; if (xlen > 0 && xlen < 200) { - PrintAndLogEx(INFO, "FCP... [%d] %s", xlen, sprint_hex(&attr[9 + keynum + 1 + keynum * 7], xlen)); + PrintAndLogEx(INFO, "TLV file control parameters... [%d] %s", xlen, sprint_hex(&attr[9 + keynum + 1 + keynum * 7], xlen)); TLVPrintFromBuffer(&attr[9 + keynum + 1 + keynum * 7], xlen); - PrintAndLogEx(INFO, ""); + PrintAndLogEx(NORMAL, ""); } } - // MF + // MF only if (attr[1] == 0x00) { PrintAndLogEx(INFO, "Total memory size... %d", (attr[len - 6] << 16) + (attr[len - 5] << 8) + attr[len - 4]); PrintAndLogEx(INFO, "Free memory size.... %d", (attr[len - 3] << 16) + (attr[len - 2] << 8) + attr[len - 1]); - } else { - int ptr = 11 + keynum + 1 + keynum * 7; - if (len > ptr) { - PrintAndLogEx(INFO, "TLV file control... %s", sprint_hex(&attr[ptr], len - ptr)); - } } } else { PrintAndLogEx(INFO, "Type... EF"); From 8318afdb60dc6cf02cb095f44139ad189ebce37a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 23:15:53 +0200 Subject: [PATCH 09/16] small fix --- client/src/cipurse/cipursecore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index a359666bb..838f5b139 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -388,8 +388,8 @@ void CIPURSEPrintART(uint8_t *artrec, size_t artlen) { else PrintAndLogEx(INFO, "key %d : " NOLF, i); - for (int n = 0; n < 8; n++) - if ((artrec[i] >> n) && 0x01) + for (int n = 7; n >= 0; n--) + if ((artrec[i] >> n) & 0x01) PrintAndLogEx(NORMAL, "%d " NOLF, n + 1); else PrintAndLogEx(NORMAL, " " NOLF); From ebeba309a4516e464adf65686103626059dbd5ad Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Feb 2022 23:59:37 +0200 Subject: [PATCH 10/16] fix file attributes decoding --- client/src/cipurse/cipursecore.c | 64 ++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 838f5b139..9d2d97df5 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -372,11 +372,10 @@ const char *CIPURSEGetSMR(uint8_t smr) { } void CIPURSEPrintSMR(uint8_t *smrrec) { - PrintAndLogEx(INFO, "%s/%s/%s/%s", - CIPURSEGetSMR((smrrec[0] >> 8) & 0x03), - CIPURSEGetSMR(smrrec[0] & 0x03), - CIPURSEGetSMR((smrrec[1] >> 8) & 0x03), - CIPURSEGetSMR(smrrec[1] & 0x03)); + PrintAndLogEx(INFO, "1. %s/%s", CIPURSEGetSMR((smrrec[0] >> 6) & 0x03), CIPURSEGetSMR((smrrec[0] >> 4) & 0x03)); + PrintAndLogEx(INFO, "2. %s/%s", CIPURSEGetSMR((smrrec[0] >> 2) & 0x03), CIPURSEGetSMR((smrrec[0] >> 0) & 0x03)); + PrintAndLogEx(INFO, "3. %s/%s", CIPURSEGetSMR((smrrec[1] >> 6) & 0x03), CIPURSEGetSMR((smrrec[1] >> 4) & 0x03)); + PrintAndLogEx(INFO, "4. %s/%s", CIPURSEGetSMR((smrrec[1] >> 2) & 0x03), CIPURSEGetSMR((smrrec[1] >> 0) & 0x03)); } void CIPURSEPrintART(uint8_t *artrec, size_t artlen) { @@ -405,11 +404,14 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { } PrintAndLogEx(INFO, "--- " _CYAN_("File Attributes") "---------------------"); - if (attr[0] == 0x38) { + if (attr[0] == 0x38 || attr[0] == 0x3F) { PrintAndLogEx(INFO, "Type... MF, ADF"); if (attr[1] == 0x00) { - PrintAndLogEx(INFO, "Type... MF"); + if (attr[0] == 0x3F) + PrintAndLogEx(INFO, "Type... PxSE"); + else + PrintAndLogEx(INFO, "Type... MF"); } else { if ((attr[1] & 0xe0) == 0x00) PrintAndLogEx(INFO, "Type... Unknown"); @@ -441,37 +443,43 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { uint8_t keynum = attr[6]; PrintAndLogEx(INFO, "Keys assigned... %d", keynum); - if (len >= 9) { - PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]); - CIPURSEPrintSMR(&attr[7]); - } - - if (len >= 9 + keynum + 1) { - PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], keynum + 1)); - CIPURSEPrintART(&attr[9], keynum + 1); - PrintAndLogEx(NORMAL, ""); - } - - if (len >= 9 + keynum + 1 + keynum * 7) { - for (int i = 0; i < keynum; i++) { - PrintAndLogEx(INFO, "Key %d Attributes... %s", i + 1, sprint_hex(&attr[9 + keynum + 1 + i * 7], 7)); - CIPURSEPrintKeyAttrib(&attr[9 + keynum + 1 + i * 7]); + int idx = 7; + if ( keynum > 0) { + if (len >= idx + 2) { + PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[idx], attr[idx + 1]); + CIPURSEPrintSMR(&attr[idx]); } + idx += 2; + + if (len >= idx + keynum + 1) { + PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[idx], keynum + 1)); + CIPURSEPrintART(&attr[idx], keynum + 1); + PrintAndLogEx(NORMAL, ""); + } + idx += keynum + 1; + + if (len >= idx + keynum * 7) { + for (int i = 0; i < keynum; i++) { + PrintAndLogEx(INFO, "Key %d Attributes... %s", i + 1, sprint_hex(&attr[idx + i * 7], 7)); + CIPURSEPrintKeyAttrib(&attr[idx + i * 7]); + } + } + idx += keynum * 7; } // FCP - if (len >= 9 + keynum + 1 + keynum * 7 + 1) { - int xlen = len - (9 + keynum + 1 + keynum * 7); + if (len >= idx + 1) { + int xlen = len - idx; // for MF only - if (attr[1] == 0x00) + if (attr[1] == 0x00 && attr[0] != 0x3F) xlen = xlen - 6; if (xlen > 0 && xlen < 200) { - PrintAndLogEx(INFO, "TLV file control parameters... [%d] %s", xlen, sprint_hex(&attr[9 + keynum + 1 + keynum * 7], xlen)); - TLVPrintFromBuffer(&attr[9 + keynum + 1 + keynum * 7], xlen); + PrintAndLogEx(INFO, "TLV file control parameters... [%d] %s", xlen, sprint_hex(&attr[idx], xlen)); + TLVPrintFromBuffer(&attr[idx], xlen); PrintAndLogEx(NORMAL, ""); } } // MF only - if (attr[1] == 0x00) { + if (attr[1] == 0x00 && attr[0] != 0x3F) { PrintAndLogEx(INFO, "Total memory size... %d", (attr[len - 6] << 16) + (attr[len - 5] << 8) + attr[len - 4]); PrintAndLogEx(INFO, "Free memory size.... %d", (attr[len - 3] << 16) + (attr[len - 2] << 8) + attr[len - 1]); From 4743c6b7f012d3b293dbfef730eaa589e2db2df7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Feb 2022 00:06:30 +0200 Subject: [PATCH 11/16] aread select sketch --- client/src/cmdhfcipurse.c | 42 +++++++++++++-------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index ab99e48ad..097fcb905 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -786,12 +786,12 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { arg_lit0("v", "verbose", "show technical data"), arg_int0("n", NULL, "", "key ID"), arg_str0("k", "key", "", "Auth key"), + arg_lit0(NULL, "mfd", "show info about master file"), + arg_str0(NULL, "aid", "", "select application ID (AID)"), arg_str0(NULL, "fid", "", "file ID"), arg_lit0(NULL, "noauth", "read file attributes without authentication"), arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), arg_str0(NULL, "sresp", "", "communication PICC-reader security level"), - arg_lit0(NULL, "sel-adf", "show info about ADF itself"), - arg_lit0(NULL, "sel-mf", "show info about master file"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -799,34 +799,37 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId); + bool selmfd = arg_get_lit(ctx, 5); CipurseChannelSecurityLevel sreq = CPSMACed; 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, 5, 7, 8, key, NULL, NULL, NULL, &fileId, &useFID, &sreq, &sresp); - if (res || useFID == false) { + uint16_t childFileId = defaultFileId; + bool useChildFID = false; + int res = CLIParseCommandParametersEx(ctx, 4, 6, 7, 0, 9, 10, key, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, &sreq, &sresp); + if (res) { CLIParserFree(ctx); return PM3_EINVARG; } - bool noAuth = arg_get_lit(ctx, 6); - bool seladf = arg_get_lit(ctx, 9); - bool selmf = arg_get_lit(ctx, 10); - - SetAPDULogging(APDULogging); + bool noAuth = arg_get_lit(ctx, 8); CLIParserFree(ctx); + SetAPDULogging(APDULogging); + uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { - PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw); DropField(); return PM3_ESOFT; } @@ -852,23 +855,6 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { CIPURSECSetActChannelSecurityLevels(sreq, sresp); } - if (seladf == false) { - if (selmf) - res = CIPURSESelectMFDefaultFile(buf, sizeof(buf), &len, &sw); - else - res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); - - if (res != 0 || sw != 0x9000) { - if (verbose == false) - PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw); - DropField(); - return PM3_ESOFT; - } - } - - if (verbose) - PrintAndLogEx(INFO, "Select file 0x%x ( " _GREEN_("ok") " )", fileId); - res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) From 49bbc0157bd6ca2daf5f8d7245104e640facc88a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 4 Feb 2022 00:58:31 +0200 Subject: [PATCH 12/16] command aread works with EF files --- client/src/cipurse/cipursecore.c | 1 + client/src/cmdhfcipurse.c | 35 +++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 9d2d97df5..61851505e 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -189,6 +189,7 @@ int CIPURSESelectFile(uint16_t fileid, uint8_t *result, size_t max_result_len, s } int CIPURSESelectMFDefaultFileEx(bool activate_field, bool leave_field_on, uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) { + CipurseCClearContext(&cipurseContext); return CIPURSEExchangeEx(activate_field, leave_field_on, (sAPDU_t) {0x00, 0xa4, 0x00, 0x00, 0, NULL}, true, 0, result, max_result_len, result_len, sw); } int CIPURSESelectMFDefaultFile(uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) { diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 097fcb905..a1c89fb23 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -777,7 +777,10 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf cipurse aread", "Read file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", - "hf cipurse aread --fid 2ff7 -> Authenticate with keyID 1, read file attributes with id 2ff7\n" + "hf cipurse aread --fid 2ff7 -> Select MF, Authenticate with keyID 1, read file attributes with id 2ff7\n" + "hf cipurse aread --mfd -> read file attributes for master file (MF)\n" + "hf cipurse aread --chfid 0102 -> read file 0102 attributes in the default application\n" + "hf cipurse aread --aid 4144204632 --chfid 0102 -> read file 0102 attributes in the 4144204632 application\n" "hf cipurse aread -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2, read file attributes\n"); void *argtable[] = { @@ -789,6 +792,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { arg_lit0(NULL, "mfd", "show info about master file"), arg_str0(NULL, "aid", "", "select application ID (AID)"), arg_str0(NULL, "fid", "", "file ID"), + arg_str0(NULL, "chfid", "", "child file ID (EF under application/master file)"), arg_lit0(NULL, "noauth", "read file attributes without authentication"), arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), arg_str0(NULL, "sresp", "", "communication PICC-reader security level"), @@ -812,13 +816,13 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { bool useFID = false; uint16_t childFileId = defaultFileId; bool useChildFID = false; - int res = CLIParseCommandParametersEx(ctx, 4, 6, 7, 0, 9, 10, key, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, &sreq, &sresp); + int res = CLIParseCommandParametersEx(ctx, 4, 6, 7, 8, 10, 11, key, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, &sreq, &sresp); if (res) { CLIParserFree(ctx); return PM3_EINVARG; } - bool noAuth = arg_get_lit(ctx, 8); + bool noAuth = arg_get_lit(ctx, 9); CLIParserFree(ctx); @@ -830,16 +834,27 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { + PrintAndLogEx(WARNING, "useaid=%d res=%d sw=%x", useAID, res, sw); DropField(); return PM3_ESOFT; } if (verbose) { - PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " key id " _YELLOW_("%d") " key " _YELLOW_("%s") - , fileId - , keyId - , sprint_hex(key, CIPURSE_AES_KEY_LENGTH) - ); + if (selmfd) + PrintAndLogEx(INFO, "File " _CYAN_("Master File")); + else if (useFID) + PrintAndLogEx(INFO, "File id " _CYAN_("%04x"), fileId); + else + PrintAndLogEx(INFO, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid, aidLen)); + + if (useChildFID) + PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x"), childFileId); + + if (!noAuth) + PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s") + , keyId + , sprint_hex(key, CIPURSE_AES_KEY_LENGTH) + ); } if (noAuth == false) { @@ -864,13 +879,13 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { } if (len == 0) { - PrintAndLogEx(WARNING, "File id " _YELLOW_("%x") " attributes is empty", fileId); + PrintAndLogEx(WARNING, "File attributes is empty"); DropField(); return PM3_SUCCESS; } if (verbose) - PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " attributes[%zu]: %s", fileId, len, sprint_hex(buf, len)); + PrintAndLogEx(INFO, "Attributes raw data [%zu]: %s", len, sprint_hex(buf, len)); CIPURSEPrintFileAttr(buf, len); From fd3b7413c3633654fa66d18f686d5ea9f5844128 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 4 Feb 2022 01:15:40 +0200 Subject: [PATCH 13/16] some info --- client/src/cipurse/cipursecore.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 61851505e..fe790602c 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -352,12 +352,20 @@ void CIPURSEPrintFileDescriptor(uint8_t desc) { PrintAndLogEx(INFO, "Unknown file 0x%02x", desc); } +static void CIPURSEPrintKeySecurityAttributes(uint8_t attr) { + PrintAndLogEx(INFO, "Update right: %s", (attr & 0x01) ? "self" : "any"); + PrintAndLogEx(INFO, "Change key and rights: %s", (attr & 0x02) ? "ok" : "frozen"); + PrintAndLogEx(INFO, "Use as key encryption key: %s", (attr & 0x04) ? "blocked" : "ok"); + PrintAndLogEx(INFO, "Key validity: %s", (attr & 0x80) ? "invalid" : "valid"); +} + static void CIPURSEPrintKeyAttrib(uint8_t *attr) { PrintAndLogEx(INFO, "--- " _CYAN_("Key Attributes") "---------------------"); PrintAndLogEx(INFO, "Additional info... 0x%02x", attr[0]); PrintAndLogEx(INFO, "Key length........ %d", attr[1]); - PrintAndLogEx(INFO, "Algorithm ID...... 0x%02x", attr[2]); + PrintAndLogEx(INFO, "Algorithm ID...... 0x%02x (%s)", attr[2], (attr[2] == 0x09) ? "AES" : "unknown"); PrintAndLogEx(INFO, "Security attr..... 0x%02x", attr[3]); + CIPURSEPrintKeySecurityAttributes(attr[3]); PrintAndLogEx(INFO, "KVV............... 0x%02x%02x%02x", attr[4], attr[5], attr[6]); PrintAndLogEx(NORMAL, ""); } From 6637eb0f3f5816da6831440d9ca4539bae0206ee Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 4 Feb 2022 12:52:13 +0200 Subject: [PATCH 14/16] print attributes refactoring --- client/src/cipurse/cipursecore.c | 108 ++++++++++++++++++++++--------- client/src/cipurse/cipursecore.h | 2 + client/src/cmdhfcipurse.c | 13 +--- 3 files changed, 82 insertions(+), 41 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index fe790602c..c11707d3d 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -352,6 +352,51 @@ void CIPURSEPrintFileDescriptor(uint8_t desc) { PrintAndLogEx(INFO, "Unknown file 0x%02x", desc); } +void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen) { + if (dgilen < 3) { + PrintAndLogEx(WARNING, "DGI too small. Length: %zu", dgilen); + return; + } + + uint8_t len = dgi[2]; + if (len + 3 != dgilen) { + PrintAndLogEx(ERR, "DGI size does not match with record size. Length of record: %zu, DGI size: %d", dgilen, len); + return; + } + + // check DGI + if (dgi[0] == 0x92 && dgi[1] == 0x00) { + PrintAndLogEx(INFO, "DGI 9200 - ADF file attributes"); + + } else if (dgi[0] == 0x92 && dgi[1] == 0x01) { + PrintAndLogEx(INFO, "DGI 9201 - EF file attributes"); + PrintAndLogEx(INFO, "File type:"); + CIPURSEPrintEFFileAttr(&dgi[3], len); + PrintAndLogEx(NORMAL, ""); + + } else if (dgi[0] == 0xa0 && dgi[1] == 0x0f) { + PrintAndLogEx(INFO, "DGI a00f - All key values"); + + if (len % 20 != 0) { + PrintAndLogEx(ERR, "Key values size must be array of 20-bite record. ADF size: %d", len); + return; + } + + for (int i = 0; i < len / 20; i++) { + PrintAndLogEx(INFO, "Key[%d]............ %s", i + 1, sprint_hex_inrow(&dgi[3 + i * 20 + 0], 16)); + PrintAndLogEx(INFO, " Additional info.. 0x%02x", dgi[3 + i * 20 + 16]); + uint8_t kvv[CIPURSE_KVV_LENGTH] = {0}; + CipurseCGetKVV(&dgi[3 + i * 20 + 0], kvv); + bool kvvvalid = (memcmp(kvv, &dgi[3 + i * 20 + 17], 3) == 0); + PrintAndLogEx(INFO, " KVV.............. %s (%s)", sprint_hex_inrow(&dgi[3 + i * 20 + 17], 3), (kvvvalid) ? _GREEN_("valid") : _RED_("invalid")); + } + PrintAndLogEx(NORMAL, ""); + + } else { + PrintAndLogEx(WARNING, "Unknown DGI %02x%02x", dgi[0], dgi[1]); + } +} + static void CIPURSEPrintKeySecurityAttributes(uint8_t attr) { PrintAndLogEx(INFO, "Update right: %s", (attr & 0x01) ? "self" : "any"); PrintAndLogEx(INFO, "Change key and rights: %s", (attr & 0x02) ? "ok" : "frozen"); @@ -406,6 +451,38 @@ void CIPURSEPrintART(uint8_t *artrec, size_t artlen) { } } +void CIPURSEPrintEFFileAttr(uint8_t *attr, size_t len) { + CIPURSEPrintFileDescriptor(attr[0]); + + if (attr[1] == 0) + PrintAndLogEx(INFO, "SFI.... not assigned"); + else + PrintAndLogEx(INFO, "SFI.... 0x%02x", attr[1]); + + PrintAndLogEx(INFO, "File ID... 0x%02x%02x", attr[2], attr[3]); + + if (attr[0] == 0x01 || attr[0] == 0x11) + PrintAndLogEx(INFO, "File size... %d", (attr[4] << 8) + attr[5]); + else + PrintAndLogEx(INFO, "Record num " _YELLOW_("%d") " record size " _YELLOW_("%d"), attr[4], attr[5]); + + PrintAndLogEx(INFO, "Keys assigned... %d", attr[6]); + + if (len >= 9) { + PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]); + CIPURSEPrintSMR(&attr[7]); + } + + if (len >= 10) { + PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], len - 9)); + CIPURSEPrintART(&attr[9], len - 9); + + if (attr[6] + 1 != len - 9) { + PrintAndLogEx(WARNING, "ART length is wrong"); + } + } +} + void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { if (len < 7) { PrintAndLogEx(FAILED, "Attributes length too short"); @@ -495,36 +572,7 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { } } else { PrintAndLogEx(INFO, "Type... EF"); - CIPURSEPrintFileDescriptor(attr[0]); - - if (attr[1] == 0) - PrintAndLogEx(INFO, "SFI.... not assigned"); - else - PrintAndLogEx(INFO, "SFI.... 0x%02x", attr[1]); - - PrintAndLogEx(INFO, "File ID... 0x%02x%02x", attr[2], attr[3]); - - if (attr[0] == 0x01 || attr[0] == 0x11) - PrintAndLogEx(INFO, "File size... %d", (attr[4] << 8) + attr[5]); - else - PrintAndLogEx(INFO, "Record num " _YELLOW_("%d") " record size " _YELLOW_("%d"), attr[4], attr[5]); - - PrintAndLogEx(INFO, "Keys assigned... %d", attr[6]); - - if (len >= 9) { - PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]); - CIPURSEPrintSMR(&attr[7]); - } - - if (len >= 10) { - PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], len - 9)); - CIPURSEPrintART(&attr[9], len - 9); - - if (attr[6] + 1 != len - 9) { - PrintAndLogEx(WARNING, "ART length is wrong"); - } - } - + CIPURSEPrintEFFileAttr(attr, len); } diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 2311c33f8..4c9a018de 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -63,7 +63,9 @@ void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, Cipurs const char *CIPURSEGetSMR(uint8_t smr); void CIPURSEPrintSMR(uint8_t *smrrec); void CIPURSEPrintART(uint8_t *artrec, size_t artlen); +void CIPURSEPrintEFFileAttr(uint8_t *attr, size_t len); void CIPURSEPrintFileAttr(uint8_t *attr, size_t len); void CIPURSEPrintFileDescriptor(uint8_t desc); +void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen); #endif /* __CIPURSECORE_H__ */ diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index a1c89fb23..af5ff0345 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -1042,17 +1042,8 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) { 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"); - } + if (verbose && hdatalen > 3) + CIPURSEPrintDGI(hdata, hdatalen); uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; From d3da7cfb065c55057271f29701ad408e268377cc Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 4 Feb 2022 14:19:57 +0200 Subject: [PATCH 15/16] dgi printing --- client/src/cipurse/cipursecore.c | 59 ++++++++++++++++++++++++-------- client/src/cipurse/cipursecore.h | 2 ++ client/src/cmdhfcipurse.c | 2 +- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index c11707d3d..6da5f7849 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -352,6 +352,23 @@ void CIPURSEPrintFileDescriptor(uint8_t desc) { PrintAndLogEx(INFO, "Unknown file 0x%02x", desc); } +void CIPURSEPrintDGIArray(uint8_t *dgi, size_t dgilen) { + if (dgilen < 3) { + PrintAndLogEx(WARNING, "DGI too small. Length: %zu", dgilen); + return; + } + + uint8_t *dgiptr = dgi; + size_t reslen = 0; + while (dgilen > reslen + 2) { + uint8_t len = dgiptr[2]; + CIPURSEPrintDGI(dgiptr, len + 3); + + dgiptr += len + 3; + reslen += len + 3; + } +} + void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen) { if (dgilen < 3) { PrintAndLogEx(WARNING, "DGI too small. Length: %zu", dgilen); @@ -367,12 +384,11 @@ void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen) { // check DGI if (dgi[0] == 0x92 && dgi[1] == 0x00) { PrintAndLogEx(INFO, "DGI 9200 - ADF file attributes"); + CIPURSEPrintFileAttrEx(&dgi[3], len, true); } else if (dgi[0] == 0x92 && dgi[1] == 0x01) { PrintAndLogEx(INFO, "DGI 9201 - EF file attributes"); - PrintAndLogEx(INFO, "File type:"); - CIPURSEPrintEFFileAttr(&dgi[3], len); - PrintAndLogEx(NORMAL, ""); + CIPURSEPrintFileAttrEx(&dgi[3], len, true); } else if (dgi[0] == 0xa0 && dgi[1] == 0x0f) { PrintAndLogEx(INFO, "DGI a00f - All key values"); @@ -398,10 +414,10 @@ void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen) { } static void CIPURSEPrintKeySecurityAttributes(uint8_t attr) { - PrintAndLogEx(INFO, "Update right: %s", (attr & 0x01) ? "self" : "any"); - PrintAndLogEx(INFO, "Change key and rights: %s", (attr & 0x02) ? "ok" : "frozen"); - PrintAndLogEx(INFO, "Use as key encryption key: %s", (attr & 0x04) ? "blocked" : "ok"); - PrintAndLogEx(INFO, "Key validity: %s", (attr & 0x80) ? "invalid" : "valid"); + PrintAndLogEx(INFO, " Update right: %s", (attr & 0x01) ? "self" : "any"); + PrintAndLogEx(INFO, " Change key and rights: %s", (attr & 0x02) ? "ok" : "frozen"); + PrintAndLogEx(INFO, " Use as key encryption key: %s", (attr & 0x04) ? "blocked" : "ok"); + PrintAndLogEx(INFO, " Key validity: %s", (attr & 0x80) ? "invalid" : "valid"); } static void CIPURSEPrintKeyAttrib(uint8_t *attr) { @@ -415,6 +431,15 @@ static void CIPURSEPrintKeyAttrib(uint8_t *attr) { PrintAndLogEx(NORMAL, ""); } +static void CIPURSEPrintKeyAttribDGI(uint8_t *attr) { + PrintAndLogEx(INFO, "--- " _CYAN_("DGI Key Attributes") "---------------------"); + PrintAndLogEx(INFO, "Security attr..... 0x%02x", attr[0]); + CIPURSEPrintKeySecurityAttributes(attr[0]); + PrintAndLogEx(INFO, "Key length........ %d", attr[1]); + PrintAndLogEx(INFO, "Algorithm ID...... 0x%02x (%s)", attr[2], (attr[2] == 0x09) ? "AES" : "unknown"); + PrintAndLogEx(NORMAL, ""); +} + const char *CIPURSEGetSMR(uint8_t smr) { switch (smr) { case 0x00: return "plain"; @@ -483,7 +508,7 @@ void CIPURSEPrintEFFileAttr(uint8_t *attr, size_t len) { } } -void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { +void CIPURSEPrintFileAttrEx(uint8_t *attr, size_t len, bool isDGI) { if (len < 7) { PrintAndLogEx(FAILED, "Attributes length too short"); return; @@ -544,13 +569,17 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { } idx += keynum + 1; - if (len >= idx + keynum * 7) { + size_t reclen = (isDGI) ? 3 : 7; + if (len >= idx + keynum * reclen) { for (int i = 0; i < keynum; i++) { - PrintAndLogEx(INFO, "Key %d Attributes... %s", i + 1, sprint_hex(&attr[idx + i * 7], 7)); - CIPURSEPrintKeyAttrib(&attr[idx + i * 7]); + PrintAndLogEx(INFO, "Key %d Attributes... %s", i + 1, sprint_hex(&attr[idx + i * reclen], reclen)); + if (isDGI) + CIPURSEPrintKeyAttribDGI(&attr[idx + i * reclen]); + else + CIPURSEPrintKeyAttrib(&attr[idx + i * reclen]); } } - idx += keynum * 7; + idx += keynum * reclen; } // FCP if (len >= idx + 1) { @@ -573,9 +602,11 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { } else { PrintAndLogEx(INFO, "Type... EF"); CIPURSEPrintEFFileAttr(attr, len); + PrintAndLogEx(NORMAL, ""); } - } - +void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { + return CIPURSEPrintFileAttrEx(attr, len, false); +} diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 4c9a018de..3a880326a 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -64,8 +64,10 @@ const char *CIPURSEGetSMR(uint8_t smr); void CIPURSEPrintSMR(uint8_t *smrrec); void CIPURSEPrintART(uint8_t *artrec, size_t artlen); void CIPURSEPrintEFFileAttr(uint8_t *attr, size_t len); +void CIPURSEPrintFileAttrEx(uint8_t *attr, size_t len, bool isDGI); void CIPURSEPrintFileAttr(uint8_t *attr, size_t len); void CIPURSEPrintFileDescriptor(uint8_t desc); +void CIPURSEPrintDGIArray(uint8_t *dgi, size_t dgilen); void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen); #endif /* __CIPURSECORE_H__ */ diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index af5ff0345..4d11d0ef9 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -1043,7 +1043,7 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) { SetAPDULogging(APDULogging); if (verbose && hdatalen > 3) - CIPURSEPrintDGI(hdata, hdatalen); + CIPURSEPrintDGIArray(hdata, hdatalen); uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; From aca7f81c4aaffa30eadb6fdc6ee289d5a958c842 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 4 Feb 2022 14:27:33 +0200 Subject: [PATCH 16/16] add aread doc --- doc/cipurse.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/cipurse.md b/doc/cipurse.md index 2c4a83bae..365b7a2fb 100644 --- a/doc/cipurse.md +++ b/doc/cipurse.md @@ -149,6 +149,30 @@ with default key and aid, perform commit (works for files with transactions mech ```hf cipurse read --fid 0102 -d abbbccdd --commit``` +### How read file attributes +^[Top](#top) + +read master file attributes +```hf cipurse aread --mfd``` + +read EF.ID_INFO root file attributes +```hf cipurse aread --fid 2ff7``` + +read PxSE application attributes +```hf cipurse aread --aid a0000005070100``` + +read application attributes +```hf cipurse aread --aid 4144204632``` + +read file (EF) attributes + +```hf cipurse aread --aid 4144204632 --chfid 0102``` + +or with default application + +```hf cipurse aread --aid 4144204632 --chfid 0102``` + + ### How to personalize card ^[Top](#top)