Skip to content

Commit

Permalink
wip ethereum personal message
Browse files Browse the repository at this point in the history
  • Loading branch information
neithanmo committed May 11, 2024
1 parent 22475ea commit e63a7a9
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 36 deletions.
3 changes: 1 addition & 2 deletions app/rust/include/rslib.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,8 @@ parser_error_t _parse_sign_hash_tx(uint8_t *input, uint16_t len);

void _clean_up_hash();

void _computeV(parser_context_t *ctx, uint8_t parity, uint8_t *v);
uint8_t _computeV(parser_context_t *ctx, uint8_t parity);

zxerr_t _process_nft_info(uint8_t *buffer, uint16_t buffer_len);

uint64_t _eth_chain_id(parser_context_t *ctx);

63 changes: 46 additions & 17 deletions app/rust/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ use crate::handlers::avax::sign_hash::{Sign as SignHash, SignUI};
use crate::handlers::avax::signing::Sign;
use crate::parser::{
parse_path_list, AvaxMessage, DisplayableItem, EthTransaction, ObjectList, PathWrapper,
U32_SIZE,
PersonalMsg, U32_SIZE,
};
use crate::parser::{FromBytes, ParserError, Transaction};
use crate::utils::ApduPanic;
use crate::ZxError;

pub mod context;
Expand All @@ -47,6 +48,12 @@ macro_rules! avax_msg_from_state {
};
}

macro_rules! eth_msg_from_state {
($ptr:expr) => {
unsafe { &mut (*addr_of_mut!((*$ptr).tx_obj.state).cast::<MaybeUninit<PersonalMsg>>()) }
};
}

/// Cast a *mut u8 to a *mut Transaction
macro_rules! eth_tx_from_state {
($ptr:expr) => {
Expand Down Expand Up @@ -77,9 +84,7 @@ pub unsafe extern "C" fn _parser_init(
Instruction::SignAvaxTx => core::mem::size_of::<MaybeUninit<Transaction>>() as u32,
Instruction::SignEthTx => core::mem::size_of::<MaybeUninit<EthTransaction>>() as u32,
Instruction::SignAvaxMsg => core::mem::size_of::<MaybeUninit<AvaxMessage>>() as u32,
Instruction::SignEthMsg => {
return ParserError::UnexpectedError as u32;
}
Instruction::SignEthMsg => core::mem::size_of::<MaybeUninit<PersonalMsg>>() as u32,
Instruction::SignAvaxHash => SIGN_HASH_TX_SIZE as u32,
};

Expand Down Expand Up @@ -177,6 +182,14 @@ pub unsafe extern "C" fn _parser_read(ctx: *const parser_context_t) -> u32 {
}
}

Instruction::SignEthMsg => {
let tx = eth_msg_from_state!(ctx as *mut parser_context_t);
match PersonalMsg::from_bytes_into(data, tx) {
Ok(_) => ParserError::ParserOk as u32,
Err(_) => ParserError::InvalidAvaxMessage as u32,
}
}

_ => ParserError::UnexpectedError as u32,
}
}
Expand Down Expand Up @@ -239,7 +252,17 @@ pub unsafe extern "C" fn _getNumItems(ctx: *const parser_context_t, num_items: *
}
}

_ => todo!(),
Instruction::SignEthMsg => {
let tx = eth_msg_from_state!(ctx as *mut parser_context_t);
let obj = tx.assume_init_mut();
match obj.num_items() {
Ok(n) => {
*num_items = n;
ParserError::ParserOk as u32
}
Err(e) => e as u32,
}
}
};

ParserError::ParserOk as u32
Expand Down Expand Up @@ -322,7 +345,17 @@ pub unsafe extern "C" fn _getItem(
}
}

_ => todo!(),
Instruction::SignEthMsg => {
let msg = eth_msg_from_state!(ctx as *mut parser_context_t);
let obj = msg.assume_init_mut();
match obj.render_item(display_idx, key, value, page_idx) {
Ok(page) => {
*page_count = page;
ParserError::ParserOk as _
}
Err(e) => e as _,
}
}
}
}

Expand Down Expand Up @@ -362,7 +395,7 @@ pub unsafe extern "C" fn _tx_data_offset(
// for eth transactions. this is required for the app_ethereum js application
// to compute the real V from this bytes
#[no_mangle]
pub unsafe extern "C" fn _computeV(ctx: *const parser_context_t, parity: u8, v: *mut u8) {
pub unsafe extern "C" fn _computeV(ctx: *const parser_context_t, parity: u8) -> u8 {
let tx = eth_tx_from_state!(ctx as *mut parser_context_t);
let data = core::slice::from_raw_parts((*ctx).buffer, (*ctx).buffer_len as _);

Expand All @@ -377,13 +410,10 @@ pub unsafe extern "C" fn _computeV(ctx: *const parser_context_t, parity: u8, v:
let len = core::cmp::min(U32_SIZE, chain_id.len());

// Check for typed transactions
// eip-1559 and eip-2930
if tx.is_typed_tx() {
// For EIP1559 and EIP2930 transactions chain_id is not empty
let id: u64 = crate::parser::bytes_to_u64(&chain_id[..len]).unwrap();
// v = (35 + parity) + (chain_id * 2)
let x: u32 = (35 + parity as u32).saturating_add((id as u32) << 1);

*v = x as u8;
// this is what the app=ethereum does
parity

// below for legacy transactions
} else if chain_id.is_empty() {
Expand All @@ -394,7 +424,7 @@ pub unsafe extern "C" fn _computeV(ctx: *const parser_context_t, parity: u8, v:
// see https://bitcoin.stackexchange.com/a/112489
// https://ethereum.stackexchange.com/a/113505
// https://eips.ethereum.org/EIPS/eip-155
*v = 27 + parity;
27 + parity
} else {
// app-ethereum reads the first 4 bytes then cast it to an u8
// this is not good but it relies on hw-eth-app lib from ledger
Expand All @@ -403,9 +433,8 @@ pub unsafe extern "C" fn _computeV(ctx: *const parser_context_t, parity: u8, v:
// Ensure that leading is not greater than U32_SIZE
// unwrap here as chain_id is neither empty nor grater that u64_size
let id: u64 = crate::parser::bytes_to_u64(&chain_id[..len]).unwrap();

//
let x: u32 = (35 + parity as u32).saturating_add((id as u32) << 1);

*v = x as u8;
x as u8
}
}
3 changes: 3 additions & 0 deletions app/rust/src/parser/coreth/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ impl<'b> FromBytes<'b> for EthTransaction<'b> {

match tx_type {
EthTransaction__Type::Legacy => {
crate::zlog("**** Legacy Transaction ****");
let out = out.as_mut_ptr() as *mut Legacy__Variant;

let legacy = unsafe { &mut *addr_of_mut!((*out).1).cast() };
Expand All @@ -233,6 +234,7 @@ impl<'b> FromBytes<'b> for EthTransaction<'b> {
}
}
EthTransaction__Type::Eip1559 => {
crate::zlog("**** EIP1559 Transaction ****");
let out = out.as_mut_ptr() as *mut Eip1559__Variant;

let eip = unsafe { &mut *addr_of_mut!((*out).1).cast() };
Expand All @@ -249,6 +251,7 @@ impl<'b> FromBytes<'b> for EthTransaction<'b> {
}
}
EthTransaction__Type::Eip2930 => {
crate::zlog("**** EIP2930 Transaction ****");
let out = out.as_mut_ptr() as *mut Eip2930__Variant;

let eip = unsafe { &mut *addr_of_mut!((*out).1).cast() };
Expand Down
134 changes: 128 additions & 6 deletions app/src/apdu_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ static bool tx_initialized = false;

bool
process_chunk_eth(__Z_UNUSED volatile uint32_t *tx, uint32_t rx);
bool
process_chunk_eth_msg(__Z_UNUSED volatile uint32_t *tx, uint32_t rx);
void
extract_eth_path(uint32_t rx, uint32_t offset);

Expand Down Expand Up @@ -255,6 +257,94 @@ process_chunk_eth(__Z_UNUSED volatile uint32_t *tx, uint32_t rx)
THROW(APDU_CODE_INVALIDP1P2);
}

bool process_chunk_eth_msg(volatile uint32_t *tx, uint32_t rx) {
zemu_log("process_chunk_eth_msg\n");
const uint8_t payloadType = G_io_apdu_buffer[OFFSET_PAYLOAD_TYPE];

if (G_io_apdu_buffer[OFFSET_P2] != 0) {
THROW(APDU_CODE_INVALIDP1P2);
}

if (rx < OFFSET_DATA) {
THROW(APDU_CODE_WRONG_LENGTH);
}

uint64_t read = 0;
uint64_t msg_len = 0;

uint8_t *data = &(G_io_apdu_buffer[OFFSET_DATA]);
uint32_t len = rx - OFFSET_DATA;
uint64_t added;
bool tx_init = false;

switch (payloadType) {
case P1_ETH_FIRST:
tx_initialize();
tx_reset();
extract_eth_path(rx, OFFSET_DATA);
uint32_t path_len = sizeof(uint32_t) * hdPath_len;
data += path_len + 1;
if (len < path_len) {
THROW(APDU_CODE_WRONG_LENGTH);
}

if (be_bytes_to_u64(data, 4, &msg_len) != 0) {
THROW(APDU_CODE_WRONG_LENGTH);
}

uint32_t remaining_len = len - path_len - 1 - 4;

// Adjust the data buffer based on the read message length
max_len = MIN(msg_len, remaining_len);
added = tx_append(data, max_len);

if (added != max_len) {
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}

// Consider transaction initialized if we handle the full length
tx_init = true;
return (remaining_len - added == 0);

case P1_ETH_MORE:
if (!tx_init) {
THROW(APDU_CODE_TX_NOT_INITIALIZED);
}

uint32_t buff_len = tx_get_buffer_length();
uint8_t *buff_data = tx_get_buffer();

// Read the expected message length from the start of the buffer
if (be_bytes_to_u64(buff_data, 4, &msg_len) != 0) {
THROW(APDU_CODE_DATA_INVALID);
}

// Ensure that the total data we expect is less than or equal to what's
// already in the buffer plus what's incoming
if (msg_len > buff_len - 4 + len) {
THROW(APDU_CODE_WRONG_LENGTH);
}

// Append new data to buffer
added = tx_append(data, len);
if (added != len) {
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}

// Update the buffer length after appending
buff_len = tx_get_buffer_length();

// Check if we've received the entire message based on the initial
// message length indicator
if (msg_len + 4 == buff_len) {
return true;
}

return false;
default:
THROW(APDU_CODE_INVALIDP1P2);
}
}
__Z_INLINE void handleGetAddr(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
zemu_log("handleGetAddr\n");

Expand Down Expand Up @@ -402,6 +492,30 @@ __Z_INLINE void handleSignAvaxMsg(volatile uint32_t *flags, volatile uint32_t *t
*flags |= IO_ASYNCH_REPLY;
}

__Z_INLINE void handleSignEthMsg(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
zemu_log("handleSignEthMsg\n");

if (!process_chunk_eth_msg(tx, rx)) {
}

const char *error_msg = tx_eth_parse_msg();
zemu_log("error\n");

CHECK_APP_CANARY()

if (error_msg != NULL) {
zemu_log(error_msg);
const int error_msg_length = strnlen(error_msg, sizeof(G_io_apdu_buffer));
memcpy(G_io_apdu_buffer, error_msg, error_msg_length);
*tx += (error_msg_length);
THROW(APDU_CODE_DATA_INVALID);
}

view_review_init(tx_getItem, tx_getNumItems, app_sign_eth_msg);
view_review_show(REVIEW_TXN);
*flags |= IO_ASYNCH_REPLY;
}

__Z_INLINE void handleSignEthTx(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
zemu_log("handleSignEthTx\n");

Expand Down Expand Up @@ -453,6 +567,15 @@ __Z_INLINE void handleNftInfo(volatile uint32_t *flags, volatile uint32_t *tx, u
*flags |= IO_ASYNCH_REPLY;
}

__Z_INLINE void handleErc20(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
zemu_log("handleErc20\n");

// nothing to do here
set_code(G_io_apdu_buffer, 0, APDU_CODE_OK);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
*flags |= IO_ASYNCH_REPLY;
}

__Z_INLINE void handleSetPlugin(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
zemu_log("handleSetPlugin\n");

Expand Down Expand Up @@ -584,12 +707,11 @@ __Z_INLINE void eth_dispatch(volatile uint32_t *flags, volatile uint32_t *tx, ui
break;
}

// case INS_ETH_PROVIDE_ERC20: {
// CHECK_PIN_VALIDATED()
// handleSignAvaxMsg(flags, tx, rx);
//
// break;
// }
case INS_ETH_PROVIDE_ERC20: {
CHECK_PIN_VALIDATED()
handleErc20(flags, tx, rx);
break;
}
//
// case INS_SIGN_ETH_MSG: {
// CHECK_PIN_VALIDATED()
Expand Down
18 changes: 18 additions & 0 deletions app/src/common/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,24 @@ __Z_INLINE void app_sign_msg() {
app_sign(0);
}

__Z_INLINE void app_sign_eth_msg() {
const uint8_t *message = tx_get_buffer();
const uint16_t messageLength = tx_get_buffer_length();
uint16_t replyLen = 0;

// MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE);
// zxerr_t err = crypto_sign_eth(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength, &replyLen);
zxerr_t err = crypto_sign_eth_msg(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, message, messageLength, &replyLen);

if (err != zxerr_ok || replyLen == 0) {
set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
} else {
set_code(G_io_apdu_buffer, replyLen, APDU_CODE_OK);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, replyLen + 2);
}
}

__Z_INLINE void app_reject() {
MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE);
set_code(G_io_apdu_buffer, 0, APDU_CODE_COMMAND_NOT_ALLOWED);
Expand Down
2 changes: 1 addition & 1 deletion app/src/common/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ parser_error_t parser_getNumItems(const parser_context_t *ctx, uint8_t *num_item
// retrieves a readable output for each field / page
parser_error_t parser_getItem(const parser_context_t *ctx, uint8_t displayIdx, char *outKey, uint16_t outKeyLen,
char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount);
parser_compute_eth_v(parser_context_t *ctx, unsigned int info, uint8_t *v);
uint8_t parser_compute_eth_v(parser_context_t *ctx, unsigned int info);

#ifdef __cplusplus
}
Expand Down
11 changes: 9 additions & 2 deletions app/src/common/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ const char *tx_avax_parse_msg() {
return tx_parse();
}

const char *tx_eth_parse_msg() {
MEMZERO(&ctx_parsed_tx.tx_obj, sizeof(parser_tx_t));
ctx_parsed_tx.ins = SignEthMsg;

return tx_parse();
}

const char *tx_eth_parse() {
MEMZERO(&ctx_parsed_tx.tx_obj, sizeof(parser_tx_t));
ctx_parsed_tx.ins = SignEthTx;
Expand Down Expand Up @@ -172,6 +179,6 @@ zxerr_t tx_getItem(int8_t displayIdx,
return zxerr_ok;
}

void tx_compute_eth_v(unsigned int info, uint8_t *v) {
parser_compute_eth_v(&ctx_parsed_tx, info, v);
uint8_t tx_compute_eth_v(unsigned int info) {
return parser_compute_eth_v(&ctx_parsed_tx, info);
}
Loading

0 comments on commit e63a7a9

Please sign in to comment.