Skip to content

Commit

Permalink
add transfer handler
Browse files Browse the repository at this point in the history
  • Loading branch information
abenso committed Sep 2, 2024
1 parent c35944b commit 8fea9ad
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 16 deletions.
142 changes: 134 additions & 8 deletions app/src/apdu_handler_legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ static bool tx_initialized = false;
static uint32_t payload_length = 0;
static uint32_t hdpath_length = 0;
static tx_type_t tx_type = tx_type_json;
static uint8_t local_data_len = 0;
static uint8_t local_data[LEGACY_LOCAL_BUFFER_SIZE];
static uint8_t items = 0;
static uint8_t item_len = 0;
static bool check_item_len = false;

__Z_INLINE void legacy_app_sign() {
const uint8_t *message = tx_get_buffer();
Expand Down Expand Up @@ -55,7 +60,7 @@ void legacy_app_reply_address() {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, action_addrResponseLen + 2);
}

void legacy_extractHDPath(uint8_t *buffer, uint32_t rx, uint32_t offset) {
void legacy_extractHDPath(uint8_t *buffer, uint32_t rx, uint32_t offset, bool check_len) {
if (rx < offset) {
THROW(APDU_CODE_WRONG_LENGTH);
}
Expand All @@ -68,8 +73,10 @@ void legacy_extractHDPath(uint8_t *buffer, uint32_t rx, uint32_t offset) {
ZEMU_LOGF(50, "hdPathLen: %d\n", hdPathLen);
ZEMU_LOGF(50, "offset_hdpath_data: %d\n", offset_hdpath_data);

if (rx - offset_hdpath_data != hdPathLen) {
THROW(APDU_CODE_WRONG_LENGTH);
if (check_len) {
if (rx - offset_hdpath_data != hdPathLen) {
THROW(APDU_CODE_WRONG_LENGTH);
}
}

MEMCPY(hdPath, buffer + offset_hdpath_data, hdPathLen);
Expand Down Expand Up @@ -114,7 +121,7 @@ uint32_t legacy_check_request(volatile uint32_t *tx) {
}

// get hdpath
legacy_extractHDPath(tx_buffer, tx_buffer_length, payload_length);
legacy_extractHDPath(tx_buffer, tx_buffer_length, payload_length, true);

// verify sizes
if (tx_buffer_length != hdpath_length + payload_length) {
Expand All @@ -127,8 +134,22 @@ uint32_t legacy_check_request(volatile uint32_t *tx) {
return tx_buffer_length - hdpath_length;
}

void legacy_append_data(uint8_t *buffer, uint32_t len) {
uint32_t added = tx_append(buffer, len);

char print[200] = {0};
array_to_hexstr(print, sizeof(print), buffer, len);
ZEMU_LOGF(200, "legacy_append_data: %s\n", print);

if (added != len) {
tx_reset();
tx_initialized = false;
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}
}

void legacy_handleGetAddr(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx, const uint8_t requireConfirmation) {
legacy_extractHDPath(G_io_apdu_buffer, rx, LEGACY_OFFSET_HDPATH_LEN);
legacy_extractHDPath(G_io_apdu_buffer, rx, LEGACY_OFFSET_HDPATH_SIZE, true);

zxerr_t zxerr = app_fill_address();
if (zxerr != zxerr_ok) {
Expand Down Expand Up @@ -178,7 +199,8 @@ bool legacy_process_chunk(__Z_UNUSED volatile uint32_t *tx, uint32_t rx, bool ha
tx_reset();
tx_initialized = true;
}


// TODO: use legacy_append_data
uint32_t added = tx_append(&(G_io_apdu_buffer[offset]), payload_size);
if (added != payload_size) {
tx_reset();
Expand All @@ -195,6 +217,105 @@ bool legacy_process_chunk(__Z_UNUSED volatile uint32_t *tx, uint32_t rx, bool ha
return false;
}

static uint32_t legacy_initialize_transfer() {
legacy_extractHDPath(G_io_apdu_buffer, LEGACY_OFFSET_HDPATH_SIZE + 1, LEGACY_OFFSET_HDPATH_SIZE, false);

tx_initialize();
tx_reset();
tx_initialized = true;

uint32_t offset = hdpath_length + LEGACY_OFFSET_HDPATH_SIZE;

// save tx_type
legacy_append_data(&G_io_apdu_buffer[offset], 1);
items = 0;

return offset;
}

static uint32_t legacy_process_existing_transfer(uint32_t *payload_size) {
legacy_append_data(local_data, local_data_len);

uint32_t offset = LEGACY_HEADER_LENGTH;

if (check_item_len) {
*payload_size = G_io_apdu_buffer[offset];
legacy_append_data(&G_io_apdu_buffer[offset], *payload_size + 1);
} else {
if (item_len <= local_data_len) {
THROW(APDU_CODE_DATA_INVALID);
}
*payload_size = item_len - local_data_len;
legacy_append_data(&G_io_apdu_buffer[offset], *payload_size);
offset--;
}

items++;
local_data_len = 0;

return offset;
}

static void legacy_handle_overflow(uint32_t offset, uint32_t payload_size) {
check_item_len = false;
item_len = payload_size + 1;

if (offset > LEGACY_FULL_CHUNK_SIZE) {
THROW(APDU_CODE_DATA_INVALID);
}
local_data_len = LEGACY_FULL_CHUNK_SIZE - offset;
if (local_data_len >= LEGACY_LOCAL_BUFFER_SIZE) {
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}
MEMCPY(local_data, &G_io_apdu_buffer[offset], local_data_len);
}

bool legacy_process_transfer_chunk(uint32_t rx) {
if (rx < LEGACY_HEADER_LENGTH) {
tx_initialized = false;
THROW(APDU_CODE_WRONG_LENGTH);
}

uint32_t payload_size = 0;
uint32_t offset = tx_initialized ? legacy_process_existing_transfer(&payload_size) : legacy_initialize_transfer();

while (offset < rx) {
offset += payload_size + 1;

if (offset > rx) {
THROW(APDU_CODE_DATA_INVALID);
}

if (offset == LEGACY_FULL_CHUNK_SIZE) {
check_item_len = true;
return false;
}

payload_size = G_io_apdu_buffer[offset];
uint32_t next_offset = offset + payload_size + 1;

if (next_offset > LEGACY_FULL_CHUNK_SIZE) {
legacy_handle_overflow(offset, payload_size);
return false;
}

legacy_append_data(&G_io_apdu_buffer[offset], payload_size + 1);

if (++items > LEGACY_TRANSFER_NUM_ITEMS) {
THROW(APDU_CODE_DATA_INVALID);
}

if (next_offset >= rx && next_offset != LEGACY_FULL_CHUNK_SIZE) {
if (items != LEGACY_TRANSFER_NUM_ITEMS) {
THROW(APDU_CODE_DATA_INVALID);
}
return true;
}
}

THROW(APDU_CODE_DATA_INVALID);
}

// bytes: | 1 | 1 | 1 | 1 | 1 | 4 | payload_len | 1 | 4*hdpath_qty |
// data: | CLA | INS | P1 | P2 | chunk_len | payload_len | payload | hdpath_qty | hdpath_data |
void legacy_handleSignTransaction(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
Expand Down Expand Up @@ -244,13 +365,16 @@ void legacy_handleSignHash(volatile uint32_t *flags, volatile uint32_t *tx, uint
*flags |= IO_ASYNCH_REPLY;
}

// bytes: | 1 | 1 | 1 | 1 | 1 | 4*hdpath_qty | n |
// data: | CLA | INS | P1 | P2 | hdpath_qty | hdpath_data | payload |
void legacy_handleSignTransferTx(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
zemu_log("handleSignLegacyTransferTx\n");
if (!legacy_process_chunk(tx, rx, false, 32)) {
if (!legacy_process_transfer_chunk(rx)) {
THROW(APDU_CODE_OK);
}

uint32_t buffer_length = legacy_check_request(tx);
uint32_t buffer_length = tx_get_buffer_length();
ZEMU_LOGF(50, "buffer_length: %d\n", buffer_length);

const char *error_msg = tx_parse(buffer_length, tx_type_transaction);
tx_type = tx_type_transaction;
Expand All @@ -262,6 +386,8 @@ void legacy_handleSignTransferTx(volatile uint32_t *flags, volatile uint32_t *tx
THROW(APDU_CODE_DATA_INVALID);
}

THROW(APDU_CODE_OK);

view_review_init(tx_getItem, tx_getNumItems, legacy_app_sign);
view_review_show(REVIEW_TXN);
*flags |= IO_ASYNCH_REPLY;
Expand Down
5 changes: 4 additions & 1 deletion app/src/apdu_handler_legacy.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@ extern "C" {

#define LEGACY_CHUNK_SIZE 230
#define LEGACY_HEADER_LENGTH 5
#define LEGACY_FULL_CHUNK_SIZE (LEGACY_CHUNK_SIZE + LEGACY_HEADER_LENGTH)
#define LEGACY_PAYLOAD_LEN_BYTES 4
#define LEGACY_OFFSET_HDPATH_LEN 5
#define LEGACY_OFFSET_HDPATH_SIZE 5
#define LEGACY_HDPATH_LEN_BYTES 1
#define LEGACY_TRANSFER_NUM_ITEMS 12
#define LEGACY_LOCAL_BUFFER_SIZE 33

void legacy_handleGetAddr(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx, const uint8_t requireConfirmation);
void legacy_handleSignTransaction(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx);
Expand Down
2 changes: 1 addition & 1 deletion tests_zemu/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@
"ts-jest": "^29.2.3",
"ts-node": "^10.9.2",
"typescript": "^5.5.4",
"hw-app-kda": "link:hw-app-kda"
"hw-app-kda": "git+https://github.com/obsidiansystems/hw-app-kda"
}
}
10 changes: 5 additions & 5 deletions tests_zemu/tests/legacy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { JSON_TEST_CASES } from './testscases/json'
import { HASH_TEST_CASES } from './testscases/hash'
import { TRANSACTIONS_TEST_CASES } from './testscases/transactions'
import { APDU_TEST_CASES } from './testscases/legacy_apdu'

// @ts-expect-error
import ed25519 from 'ed25519-supercop'

Expand Down Expand Up @@ -106,7 +105,7 @@ test.concurrent.each(models)('legacy show address - reject', async function (m)
})

describe.each(JSON_TEST_CASES)('Tx transactions', function (data) {
test.only.each(models)('sign json', async function (m) {
test.concurrent.each(models)('sign json', async function (m) {
const sim = new Zemu(m.path)
try {
await sim.start({ ...defaultOptions, model: m.name })
Expand Down Expand Up @@ -183,18 +182,19 @@ describe.each(HASH_TEST_CASES)('Hash transactions', function (data) {
})

describe.each(TRANSACTIONS_TEST_CASES)('Tx transactions', function (data) {
test.concurrent.each(models)('sign', async function (m) {
test.only.each(models)('sign', async function (m) {
const sim = new Zemu(m.path)
try {
await sim.start({ ...defaultOptions, model: m.name })
const app = new Kda(sim.getTransport());

const responseAddr = await app.getPublicKey(data.path)
const responseAddr = await app.getPublicKey(data.txParams.path)
const pubKey = responseAddr.publicKey
console.log(pubKey)


// do not wait here... we need to navigate
const signatureRequest = app.signTransferTx(data.path, data)
let signatureRequest = await app["signTransferTx"](data.txParams);

// // Wait until we are not in the main menu
// await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot())
Expand Down
1 change: 1 addition & 0 deletions tests_zemu/tests/testscases/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PATH } from '../common'
import { TransferTxType } from '@zondax/ledger-kadena'
import Kda from "hw-app-kda";

export const TRANSACTIONS_TEST_CASES = [
{
Expand Down
2 changes: 1 addition & 1 deletion tests_zemu/tests/transactions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe.each(TRANSACTIONS_TEST_CASES)('Tx transactions', function (data) {
await sim.start({ ...defaultOptions, model: m.name })
const app = new KadenaApp(sim.getTransport())

const responseAddr = await app.getAddressAndPubKey(data.path)
const responseAddr = await app.getAddressAndPubKey(data.txParams.path)
const pubKey = responseAddr.pubkey

var signatureRequest = null;
Expand Down

1 comment on commit 8fea9ad

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cpp-Linter Report ⚠️

Some files did not pass the configured checks!

clang-format reports: 11 file(s) not formatted
  • app/src/crypto.c
  • app/src/parser_impl.c
  • app/src/items.c
  • app/src/apdu_handler_legacy.c
  • app/src/parser.c
  • app/src/items_format.h
  • app/src/crypto.h
  • app/src/items.h
  • app/src/parser_txdef.h
  • app/src/parser_impl.h
  • app/src/common/tx.h

Have any feedback or feature suggestions? Share it here.

Please sign in to comment.