Fix secure channel issues with 'hf mfdes createdelegateapp'

This commit is contained in:
kormax
2026-04-05 22:09:12 +03:00
parent a72f66bcbb
commit 909e1c3f23
2 changed files with 49 additions and 25 deletions
+1 -8
View File
@@ -3555,7 +3555,7 @@ static int CmdHF14ADesCreateDelegateApp(const char *Cmd) {
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
arg_str0("c", "ccset", "<native|niso|iso>", "Communicaton command set"),
arg_str0(NULL, "schann", "<d40|ev1>", "Secure channel"),
arg_str0(NULL, "schann", "<d40|ev1|ev2|lrp>", "Secure channel"),
arg_str0(NULL, "aid", "<hex>", "Application ID for create. Mandatory in structured mode. (3 hex bytes, big endian)"),
arg_str0(NULL, "damslot", "<hex>", "DAM slot number (2 hex bytes, little endian on card)"),
arg_str0(NULL, "damslotver", "<hex>", "DAM slot version (1 hex byte, def: 00)"),
@@ -3683,13 +3683,6 @@ static int CmdHF14ADesCreateDelegateApp(const char *Cmd) {
uint8_t contdata[250] = {0};
size_t contdatalen = 0;
// Fixing EV2 mac calculation requires changes in multiple places (command chaining, counter increment modification, etc.)
// and is not worth the effort at the moment, so we just block it for now.
if (securechann == DACEV2) {
PrintAndLogEx(ERR, "CreateDelegatedApplication is not currently implemented for EV2 secure channel (EV2 MAC calculation issues)");
return PM3_EINVARG;
}
if (appid == 0x000000) {
PrintAndLogEx(ERR, "Creating the root aid (0x000000) is " _RED_("forbidden"));
return PM3_ESOFT;
+48 -17
View File
@@ -548,7 +548,7 @@ static int DESFIRESendRaw(bool activate_field, uint8_t *data, size_t datalen, ui
return PM3_SUCCESS;
}
static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) {
static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize, size_t firsttxdatalen) {
if (resplen) {
*resplen = 0;
}
@@ -576,11 +576,21 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uin
int res;
size_t len;
size_t firsttxlen = 0;
if (firsttxdatalen > 0 && firsttxdatalen < datalen) {
firsttxlen = firsttxdatalen + 1; // +1 for the initial command byte.
if (firsttxlen > DESFIRE_TX_FRAME_MAX_LEN) {
firsttxlen = DESFIRE_TX_FRAME_MAX_LEN;
}
}
// tx chaining
size_t sentdatalen = 0;
while (cdatalen > sentdatalen) {
if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN) {
if (sentdatalen == 0 && firsttxlen > 0) {
len = firsttxlen;
} else if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN) {
len = DESFIRE_TX_FRAME_MAX_LEN;
} else {
len = cdatalen - sentdatalen;
@@ -683,7 +693,7 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uin
return PM3_SUCCESS;
}
static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) {
static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize, size_t firsttxdatalen) {
if (resplen) {
*resplen = 0;
}
@@ -711,12 +721,22 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
};
int res;
size_t firsttxlen = 0;
if (firsttxdatalen > 0 && firsttxdatalen < datalen) {
firsttxlen = firsttxdatalen;
if (firsttxlen > DESFIRE_TX_FRAME_MAX_LEN) {
firsttxlen = DESFIRE_TX_FRAME_MAX_LEN;
}
}
// tx chaining
size_t sentdatalen = 0;
bool first_tx_frame = true;
while (first_tx_frame || datalen > sentdatalen) {
first_tx_frame = false;
if (datalen - sentdatalen > DESFIRE_TX_FRAME_MAX_LEN) {
if (sentdatalen == 0 && firsttxlen > 0) {
apdu.Lc = firsttxlen;
} else if (datalen - sentdatalen > DESFIRE_TX_FRAME_MAX_LEN) {
apdu.Lc = DESFIRE_TX_FRAME_MAX_LEN;
} else {
apdu.Lc = datalen - sentdatalen;
@@ -876,8 +896,8 @@ static void DesfireSplitBytesToBlock(uint8_t *blockdata, size_t *blockdatacount,
}
}
int DesfireExchangeEx(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode,
uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) {
static int DesfireExchangeExSplit(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode,
uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize, size_t firsttxdatalen) {
int res = PM3_SUCCESS;
if (PrintChannelModeWarning(cmd, ctx->secureChannel, ctx->cmdSet, ctx->commMode) == false) {
@@ -898,9 +918,9 @@ int DesfireExchangeEx(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, u
DesfireSecureChannelEncode(ctx, cmd, data, datalen, databuf, &databuflen);
if (ctx->cmdSet == DCCNative) {
res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize, firsttxdatalen);
} else {
res = DesfireExchangeISONative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
res = DesfireExchangeISONative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize, firsttxdatalen);
}
if (splitbysize) {
@@ -928,6 +948,11 @@ int DesfireExchangeEx(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, u
return res;
}
int DesfireExchangeEx(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode,
uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) {
return DesfireExchangeExSplit(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining, splitbysize, 0);
}
int DesfireExchange(DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen) {
return DesfireExchangeEx(false, ctx, cmd, data, datalen, respcode, resp, resplen, true, 0);
}
@@ -2196,18 +2221,24 @@ int DesfireCreateDelegatedApplication(DesfireContext_t *dctx, uint8_t *appdata,
return PM3_EINVARG;
}
if (appdatalen == 0 || contdatalen == 0) {
return PM3_EINVARG;
}
if (appdatalen > DESFIRE_BUFFER_SIZE - contdatalen) {
return PM3_EINVARG;
}
uint8_t fulldata[DESFIRE_BUFFER_SIZE] = {0};
memcpy(fulldata, appdata, appdatalen);
memcpy(&fulldata[appdatalen], contdata, contdatalen);
uint8_t resp[DESFIRE_BUFFER_SIZE] = {0};
size_t resplen = 0;
uint8_t respcode = 0xFF;
int res = DesfireExchangeEx(false, dctx, MFDES_CREATE_DELEGATE_APP, appdata, appdatalen, &respcode, resp, &resplen, false, 0);
if (res != PM3_SUCCESS) {
return res;
}
if (respcode != MFDES_ADDITIONAL_FRAME) {
return PM3_EAPDU_FAIL;
}
res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, contdata, contdatalen, &respcode, resp, &resplen, false, 0);
// CreateDelegatedApplication must go out as C9 + AF frames, but secure messaging
// state (CMAC IV / cmd counter) must be advanced as a single logical command.
int res = DesfireExchangeExSplit(false, dctx, MFDES_CREATE_DELEGATE_APP, fulldata, appdatalen + contdatalen, &respcode, resp, &resplen, true, 0, appdatalen);
if (res != PM3_SUCCESS) {
return res;
}