Merge branch 'master' of github.com:LedgerHQ/app-ethereum into fix_security_and_display_issues

This commit is contained in:
pscott
2021-05-04 12:14:44 +02:00
14 changed files with 464 additions and 144 deletions

View File

@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.7.0](https://github.com/ledgerhq/app-ethereum/compare/1.6.6...1.7.0) - 2021-4-30
### Added
- Wallet ID feature now available on Nano X
## [1.6.6](https://github.com/ledgerhq/app-ethereum/compare/1.6.5...1.6.6) - 2021-4-16
### Added
- Improved Starkware support
## [1.6.5](https://github.com/ledgerhq/app-ethereum/compare/1.6.4...1.6.5) - 2021-2-12
### Added
- Add a setting to enable nonce display when approving transactions
## [1.6.4](https://github.com/ledgerhq/app-ethereum/compare/1.6.3...1.6.4) - 2021-1-12
### Fixed

View File

@@ -26,11 +26,11 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS)
# Allow the app to use path 45 for multi-sig (see BIP45).
APP_LOAD_PARAMS += --path "45'"
# Samsung temporary implementation for wallet ID on 0xda7aba5e/0xc1a551c5
#APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
APPVERSION_M=1
APPVERSION_N=6
APPVERSION_P=6
APPVERSION_N=7
APPVERSION_P=0
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION)
@@ -249,8 +249,16 @@ DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX
else
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=72
DEFINES += HAVE_WALLET_ID_SDK
endif
# Enables direct data signing without having to specify it in the settings. Useful when testing with speculos.
ALLOW_DATA:=0
ifneq ($(ALLOW_DATA),0)
DEFINES += HAVE_ALLOW_DATA
endif
# Enabling debug PRINTF
DEBUG:=0
ifneq ($(DEBUG),0)

View File

@@ -473,6 +473,8 @@ The following standard Status Words are returned for all APDUs - some specific S
[width="80%"]
|===============================================================================================
| *SW* | *Description*
| 6501 | TransactionType not supported
| 6502 | Output buffer too small for snprintf input
| 6700 | Incorrect length
| 6982 | Security status not satisfied (Canceled by user)
| 6A80 | Invalid data

View File

@@ -61,4 +61,6 @@ typedef struct chain_config_s {
chain_kind_t kind;
} chain_config_t;
#define ETHEREUM_MAINNET_CHAINID 1
#endif /* _CHAIN_CONFIG_H_ */

View File

@@ -373,11 +373,47 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
return NULL;
}
unsigned int const U_os_perso_seed_cookie[] = {
0xda7aba5e,
0xc1a551c5,
};
#ifndef HAVE_WALLET_ID_SDK
void handleGetWalletId(volatile unsigned int *tx) {
unsigned char t[64];
cx_ecfp_256_private_key_t priv;
cx_ecfp_256_public_key_t pub;
// seed => priv key
os_perso_derive_node_bip32(CX_CURVE_256K1, U_os_perso_seed_cookie, 2, t, NULL);
// priv key => pubkey
cx_ecdsa_init_private_key(CX_CURVE_256K1, t, 32, &priv);
cx_ecfp_generate_pair(CX_CURVE_256K1, &pub, &priv, 1);
// pubkey -> sha512
cx_hash_sha512(pub.W, sizeof(pub.W), t, sizeof(t));
// ! cookie !
os_memmove(G_io_apdu_buffer, t, 64);
*tx = 64;
THROW(0x9000);
}
#endif
void handleApdu(unsigned int *flags, unsigned int *tx) {
unsigned short sw = 0;
BEGIN_TRY {
TRY {
#ifndef HAVE_WALLET_ID_SDK
if ((G_io_apdu_buffer[OFFSET_CLA] == COMMON_CLA) &&
(G_io_apdu_buffer[OFFSET_INS] == COMMON_INS_GET_WALLET_ID)) {
handleGetWalletId(tx);
return;
}
#endif
#ifdef HAVE_STARKWARE
if (G_io_apdu_buffer[OFFSET_CLA] == STARKWARE_CLA) {
@@ -714,7 +750,11 @@ void coin_main(chain_config_t *coin_config) {
if (N_storage.initialized != 0x01) {
internalStorage_t storage;
#ifdef HAVE_ALLOW_DATA
storage.dataAllowed = 0x01;
#else
storage.dataAllowed = 0x00;
#endif
storage.contractDetails = 0x00;
storage.displayNonce = 0x00;
storage.initialized = 0x01;

View File

@@ -158,7 +158,9 @@ typedef struct txStringProperties_t {
char fullAddress[43];
char fullAmount[50];
char maxFee[50];
char nonce[8]; // 10M tx per account ought to be enough for everybody
char nonce[8]; // 10M tx per account ought to be enough for everybody
char chainID[8]; // 10M different chainID ought to be enough for people to find a unique
// chainID for their token / chain.
} txStringProperties_t;
typedef struct strDataTmp_t {

View File

@@ -53,22 +53,23 @@ int local_strchr(char *string, char ch) {
return -1;
}
uint32_t getV(txContent_t *txContent) {
uint32_t v = 0;
if (txContent->vLength == 1) {
v = txContent->v[0];
} else if (txContent->vLength == 2) {
v = (txContent->v[0] << 8) | txContent->v[1];
} else if (txContent->vLength == 3) {
v = (txContent->v[0] << 16) | (txContent->v[1] << 8) | txContent->v[2];
} else if (txContent->vLength == 4) {
v = (txContent->v[0] << 24) | (txContent->v[1] << 16) | (txContent->v[2] << 8) |
txContent->v[3];
} else if (txContent->vLength != 0) {
PRINTF("Unexpected v format\n");
// Almost like U4BE except that it takes `size` as a parameter.
// The `strict` parameter defines whether we should throw in case of a length > 4.
uint32_t u32_from_BE(uint8_t *in, uint8_t size, bool strict) {
uint32_t res = 0;
if (size == 1) {
res = in[0];
} else if (size == 2) {
res = (in[0] << 8) | in[1];
} else if (size == 3) {
res = (in[0] << 16) | (in[1] << 8) | in[2];
} else if (size == 4) {
res = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
} else if (strict && size != 0) {
PRINTF("Unexpected format\n");
THROW(EXCEPTION);
}
return v;
return res;
}
void amountToString(uint8_t *amount,

View File

@@ -28,7 +28,9 @@ void convertUint256BE(uint8_t* data, uint32_t length, uint256_t* target);
int local_strchr(char* string, char ch);
uint32_t getV(txContent_t* txContent);
// Converts a list of bytes (in BE) of length `size` to a uint32_t. `strict` will make the function
// throw if the size is > 4.
uint32_t u32_from_BE(uint8_t* in, uint8_t size, bool strict);
void amountToString(uint8_t* amount,
uint8_t amount_len,

View File

@@ -20,6 +20,7 @@
#include "ethUstream.h"
#include "ethUtils.h"
#include "utils.h"
#define MAX_INT256 32
#define MAX_ADDRESS 20
@@ -30,12 +31,15 @@ void initTx(txContext_t *context,
txContent_t *content,
ustreamProcess_t customProcessor,
void *extra) {
uint8_t save = context->txType;
memset(context, 0, sizeof(txContext_t));
context->txType = save;
context->sha3 = sha3;
context->content = content;
context->customProcessor = customProcessor;
context->extra = extra;
context->currentField = TX_RLP_CONTENT;
context->currentField = RLP_NONE + 1;
cx_keccak_init(context->sha3, 256);
}
@@ -86,6 +90,22 @@ static void processContent(txContext_t *context) {
context->processingField = false;
}
static void processAccessList(txContext_t *context) {
if (!context->currentFieldIsList) {
PRINTF("Invalid type for RLP_DATA\n");
THROW(EXCEPTION);
}
if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize =
MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, NULL, copySize);
}
if (context->currentFieldPos == context->currentFieldLength) {
context->currentField++;
context->processingField = false;
}
}
static void processType(txContext_t *context) {
if (context->currentFieldIsList) {
PRINTF("Invalid type for RLP_TYPE\n");
@@ -106,6 +126,27 @@ static void processType(txContext_t *context) {
}
}
static void processChainID(txContext_t *context) {
if (context->currentFieldIsList) {
PRINTF("Invalid type for RLP_CHAINID\n");
THROW(EXCEPTION);
}
if (context->currentFieldLength > MAX_INT256) {
PRINTF("Invalid length for RLP_CHAINID\n");
THROW(EXCEPTION);
}
if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize =
MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, context->content->chainID.value, copySize);
}
if (context->currentFieldPos == context->currentFieldLength) {
context->content->chainID.length = context->currentFieldLength;
context->currentField++;
context->processingField = false;
}
}
static void processNonce(txContext_t *context) {
if (context->currentFieldIsList) {
PRINTF("Invalid type for RLP_NONCE\n");
@@ -148,6 +189,11 @@ static void processStartGas(txContext_t *context) {
}
}
// Alias over `processStartGas()`.
static void processGasLimit(txContext_t *context) {
processStartGas(context);
}
static void processGasprice(txContext_t *context) {
if (context->currentFieldIsList) {
PRINTF("Invalid type for RLP_GASPRICE\n");
@@ -248,15 +294,155 @@ static void processV(txContext_t *context) {
}
}
static bool processEIP2930Tx(txContext_t *context) {
switch (context->currentField) {
case EIP2930_RLP_CONTENT:
processContent(context);
if ((context->processingFlags & TX_FLAG_TYPE) == 0) {
context->currentField++;
}
break;
case EIP2930_RLP_TYPE:
processType(context);
break;
case EIP2930_RLP_CHAINID:
processChainID(context);
break;
case EIP2930_RLP_NONCE:
processNonce(context);
break;
case EIP2930_RLP_GASPRICE:
processGasprice(context);
break;
case EIP2930_RLP_GASLIMIT:
processGasLimit(context);
break;
case EIP2930_RLP_TO:
processTo(context);
break;
case EIP2930_RLP_VALUE:
processValue(context);
break;
case EIP2930_RLP_YPARITY:
processV(context);
break;
case EIP2930_RLP_ACCESS_LIST:
processAccessList(context);
break;
case EIP2930_RLP_DATA:
case EIP2930_RLP_SENDER_R:
case EIP2930_RLP_SENDER_S:
processData(context);
break;
default:
PRINTF("Invalid RLP decoder context\n");
return true;
}
return false;
}
static bool processLegacyTx(txContext_t *context) {
switch (context->currentField) {
case LEGACY_RLP_CONTENT:
processContent(context);
if ((context->processingFlags & TX_FLAG_TYPE) == 0) {
context->currentField++;
}
break;
case LEGACY_RLP_TYPE:
processType(context);
break;
case LEGACY_RLP_NONCE:
processNonce(context);
break;
case LEGACY_RLP_GASPRICE:
processGasprice(context);
break;
case LEGACY_RLP_STARTGAS:
processStartGas(context);
break;
case LEGACY_RLP_TO:
processTo(context);
break;
case LEGACY_RLP_VALUE:
processValue(context);
break;
case LEGACY_RLP_DATA:
case LEGACY_RLP_R:
case LEGACY_RLP_S:
processData(context);
break;
case LEGACY_RLP_V:
processV(context);
break;
default:
PRINTF("Invalid RLP decoder context\n");
return true;
}
return false;
}
static parserStatus_e parseRLP(txContext_t *context) {
bool canDecode = false;
uint32_t offset;
while (context->commandLength != 0) {
bool valid;
// Feed the RLP buffer until the length can be decoded
context->rlpBuffer[context->rlpBufferPos++] = readTxByte(context);
if (rlpCanDecode(context->rlpBuffer, context->rlpBufferPos, &valid)) {
// Can decode now, if valid
if (!valid) {
PRINTF("RLP pre-decode error\n");
return USTREAM_FAULT;
}
canDecode = true;
break;
}
// Cannot decode yet
// Sanity check
if (context->rlpBufferPos == sizeof(context->rlpBuffer)) {
PRINTF("RLP pre-decode logic error\n");
return USTREAM_FAULT;
}
}
if (!canDecode) {
PRINTF("Can't decode\n");
return USTREAM_PROCESSING;
}
// Ready to process this field
if (!rlpDecodeLength(context->rlpBuffer,
context->rlpBufferPos,
&context->currentFieldLength,
&offset,
&context->currentFieldIsList)) {
PRINTF("RLP decode error\n");
return USTREAM_FAULT;
}
if (offset == 0) {
// Hack for single byte, self encoded
context->workBuffer--;
context->commandLength++;
context->fieldSingleByte = true;
} else {
context->fieldSingleByte = false;
}
context->currentFieldPos = 0;
context->rlpBufferPos = 0;
context->processingField = true;
return USTREAM_CONTINUE;
}
static parserStatus_e processTxInternal(txContext_t *context) {
for (;;) {
customStatus_e customStatus = CUSTOM_NOT_HANDLED;
// EIP 155 style transasction
if (context->currentField == TX_RLP_DONE) {
// EIP 155 style transaction
if (PARSING_IS_DONE(context)) {
return USTREAM_FINISHED;
}
// Old style transaction
if ((context->currentField == TX_RLP_V) && (context->commandLength == 0)) {
if ((context->currentField == LEGACY_RLP_V ||
context->currentField == EIP2930_RLP_YPARITY) &&
(context->commandLength == 0)) {
context->content->vLength = 0;
return USTREAM_FINISHED;
}
@@ -264,51 +450,10 @@ static parserStatus_e processTxInternal(txContext_t *context) {
return USTREAM_PROCESSING;
}
if (!context->processingField) {
bool canDecode = false;
uint32_t offset;
while (context->commandLength != 0) {
bool valid;
// Feed the RLP buffer until the length can be decoded
context->rlpBuffer[context->rlpBufferPos++] = readTxByte(context);
if (rlpCanDecode(context->rlpBuffer, context->rlpBufferPos, &valid)) {
// Can decode now, if valid
if (!valid) {
PRINTF("RLP pre-decode error\n");
return USTREAM_FAULT;
}
canDecode = true;
break;
}
// Cannot decode yet
// Sanity check
if (context->rlpBufferPos == sizeof(context->rlpBuffer)) {
PRINTF("RLP pre-decode logic error\n");
return USTREAM_FAULT;
}
parserStatus_e status = parseRLP(context);
if (status != USTREAM_CONTINUE) {
return status;
}
if (!canDecode) {
return USTREAM_PROCESSING;
}
// Ready to process this field
if (!rlpDecodeLength(context->rlpBuffer,
context->rlpBufferPos,
&context->currentFieldLength,
&offset,
&context->currentFieldIsList)) {
PRINTF("RLP decode error\n");
return USTREAM_FAULT;
}
if (offset == 0) {
// Hack for single byte, self encoded
context->workBuffer--;
context->commandLength++;
context->fieldSingleByte = true;
} else {
context->fieldSingleByte = false;
}
context->currentFieldPos = 0;
context->rlpBufferPos = 0;
context->processingField = true;
}
if (context->customProcessor != NULL) {
customStatus = context->customProcessor(context);
@@ -327,41 +472,25 @@ static parserStatus_e processTxInternal(txContext_t *context) {
}
}
if (customStatus == CUSTOM_NOT_HANDLED) {
switch (context->currentField) {
case TX_RLP_CONTENT:
processContent(context);
if ((context->processingFlags & TX_FLAG_TYPE) == 0) {
context->currentField++;
PRINTF("Current field: %u\n", context->currentField);
switch (context->txType) {
bool fault;
case LEGACY:
fault = processLegacyTx(context);
if (fault) {
return USTREAM_FAULT;
} else {
break;
}
case EIP2930:
fault = processEIP2930Tx(context);
if (fault) {
return USTREAM_FAULT;
} else {
break;
}
break;
case TX_RLP_TYPE:
processType(context);
break;
case TX_RLP_NONCE:
processNonce(context);
break;
case TX_RLP_GASPRICE:
processGasprice(context);
break;
case TX_RLP_STARTGAS:
processStartGas(context);
break;
case TX_RLP_VALUE:
processValue(context);
break;
case TX_RLP_TO:
processTo(context);
break;
case TX_RLP_DATA:
case TX_RLP_R:
case TX_RLP_S:
processData(context);
break;
case TX_RLP_V:
processV(context);
break;
default:
PRINTF("Invalid RLP decoder context\n");
PRINTF("Transaction type %u is not supported\n", context->txType);
return USTREAM_FAULT;
}
}

View File

@@ -37,27 +37,63 @@ typedef customStatus_e (*ustreamProcess_t)(struct txContext_t *context);
#define TX_FLAG_TYPE 0x01
typedef enum rlpTxField_e {
TX_RLP_NONE = 0,
TX_RLP_CONTENT,
TX_RLP_TYPE,
TX_RLP_NONCE,
TX_RLP_GASPRICE,
TX_RLP_STARTGAS,
TX_RLP_TO,
TX_RLP_VALUE,
TX_RLP_DATA,
TX_RLP_V,
TX_RLP_R,
TX_RLP_S,
TX_RLP_DONE
} rlpTxField_e;
// First variant of every Tx enum.
#define RLP_NONE 0
#define PARSING_IS_DONE(ctx) \
((ctx->txType == LEGACY && ctx->currentField == LEGACY_RLP_DONE) || \
(ctx->txType == EIP2930 && ctx->currentField == EIP2930_RLP_DONE))
typedef enum rlpLegacyTxField_e {
LEGACY_RLP_NONE = RLP_NONE,
LEGACY_RLP_CONTENT,
LEGACY_RLP_TYPE,
LEGACY_RLP_NONCE,
LEGACY_RLP_GASPRICE,
LEGACY_RLP_STARTGAS,
LEGACY_RLP_TO,
LEGACY_RLP_VALUE,
LEGACY_RLP_DATA,
LEGACY_RLP_V,
LEGACY_RLP_R,
LEGACY_RLP_S,
LEGACY_RLP_DONE
} rlpLegacyTxField_e;
typedef enum rlpEIP2930TxField_e {
EIP2930_RLP_NONE = RLP_NONE,
EIP2930_RLP_CONTENT,
EIP2930_RLP_TYPE,
EIP2930_RLP_CHAINID,
EIP2930_RLP_NONCE,
EIP2930_RLP_GASPRICE,
EIP2930_RLP_GASLIMIT,
EIP2930_RLP_TO,
EIP2930_RLP_VALUE,
EIP2930_RLP_DATA,
EIP2930_RLP_ACCESS_LIST,
EIP2930_RLP_YPARITY,
EIP2930_RLP_SENDER_R,
EIP2930_RLP_SENDER_S,
EIP2930_RLP_DONE
} rlpEIP2930TxField_e;
#define MIN_TX_TYPE 0x00
#define MAX_TX_TYPE 0x7f
// EIP 2718 TransactionType
// Valid transaction types should be in [0x00, 0x7f]
typedef enum txType_e {
EIP2930 = 0x01,
LEGACY = 0xc0 // Legacy tx are greater than or equal to 0xc0.
} txType_e;
typedef enum parserStatus_e {
USTREAM_PROCESSING,
USTREAM_SUSPENDED,
USTREAM_FINISHED,
USTREAM_FAULT
USTREAM_PROCESSING, // Parsing is in progress
USTREAM_SUSPENDED, // Parsing has been suspended
USTREAM_FINISHED, // Parsing is done
USTREAM_FAULT, // An error was encountered while parsing
USTREAM_CONTINUE // Used internally to signify we can keep on parsing
} parserStatus_e;
typedef struct txInt256_t {
@@ -70,6 +106,7 @@ typedef struct txContent_t {
txInt256_t startgas;
txInt256_t value;
txInt256_t nonce;
txInt256_t chainID;
uint8_t destination[20];
uint8_t destinationLength;
uint8_t v[4];
@@ -77,7 +114,7 @@ typedef struct txContent_t {
} txContent_t;
typedef struct txContext_t {
rlpTxField_e currentField;
uint8_t currentField;
cx_sha3_t *sha3;
uint32_t currentFieldLength;
uint32_t currentFieldPos;
@@ -93,6 +130,7 @@ typedef struct txContext_t {
ustreamProcess_t customProcessor;
txContent_t *content;
void *extra;
uint8_t txType;
} txContext_t;
void initTx(txContext_t *context,

View File

@@ -40,6 +40,22 @@ void handleSign(uint8_t p1,
}
dataPresent = false;
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_UNAVAILABLE;
// EIP 2718: TransactionType might be present before the TransactionPayload.
uint8_t txType = *workBuffer;
if (txType >= MIN_TX_TYPE && txType <= MAX_TX_TYPE) {
// Enumerate through all supported txTypes here...
if (txType == EIP2930) {
txContext.txType = txType;
workBuffer++;
dataLength--;
} else {
PRINTF("Transaction type not supported\n");
THROW(0x6501);
}
} else {
txContext.txType = LEGACY;
}
initTx(&txContext, &global_sha3, &tmpContent.txContent, customProcessor, NULL);
} else if (p1 != P1_MORE) {
THROW(0x6B00);
@@ -51,7 +67,7 @@ void handleSign(uint8_t p1,
PRINTF("Signature not initialized\n");
THROW(0x6985);
}
if (txContext.currentField == TX_RLP_NONE) {
if (txContext.currentField == RLP_NONE) {
PRINTF("Parser not initialized\n");
THROW(0x6985);
}

View File

@@ -28,12 +28,18 @@ uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
}
customStatus_e customProcessor(txContext_t *context) {
if ((context->currentField == TX_RLP_DATA) && (context->currentFieldLength != 0)) {
if (((context->txType == LEGACY && context->currentField == LEGACY_RLP_DATA) ||
(context->txType == EIP2930 && context->currentField == EIP2930_RLP_DATA)) &&
(context->currentFieldLength != 0)) {
dataPresent = true;
// If handling a new contract rather than a function call, abort immediately
if (tmpContent.txContent.destinationLength == 0) {
return CUSTOM_NOT_HANDLED;
}
// If data field is less than 4 bytes long, do not try to use a plugin.
if (context->currentFieldLength < 4) {
return CUSTOM_NOT_HANDLED;
}
if (context->currentFieldPos == 0) {
ethPluginInitContract_t pluginInit;
// If handling the beginning of the data field, assume that the function selector is
@@ -242,10 +248,22 @@ void finalizeParsing(bool direct) {
// Verify the chain
if (chainConfig->chainId != 0) {
uint32_t v = getV(&tmpContent.txContent);
if (chainConfig->chainId != v) {
uint32_t id = 0;
if (txContext.txType == LEGACY) {
id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
} else if (txContext.txType == EIP2930) {
id = u32_from_BE(txContext.content->chainID.value,
txContext.content->chainID.length,
false);
} else {
PRINTF("TxType `%u` not supported while checking for chainID\n", txContext.txType);
return;
}
if (chainConfig->chainId != id) {
PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId);
reset_app_context();
PRINTF("Invalid chainId %d expected %d\n", v, chainConfig->chainId);
reportFinalizeError(direct);
if (!direct) {
return;
@@ -327,7 +345,6 @@ void finalizeParsing(bool direct) {
}
if (dataPresent && !N_storage.dataAllowed) {
PRINTF("Data field forbidden\n");
reportFinalizeError(direct);
if (!direct) {
return;
@@ -372,6 +389,31 @@ void finalizeParsing(bool direct) {
compareOrCopy(strings.common.maxFee, displayBuffer, called_from_swap);
}
// Prepare chainID field
if (genericUI) {
if (txContext.txType == LEGACY) {
uint32_t id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
PRINTF("Chain ID: %u\n", id);
uint8_t res =
snprintf(strings.common.chainID, sizeof(strings.common.chainID), "%d", id);
if (res >= sizeof(strings.common.chainID)) {
// If the return value is higher or equal to the size passed in as parameter, then
// the output was truncated. Return the appropriate error code.
THROW(0x6502);
}
} else if (txContext.txType == EIP2930) {
uint256_t chainID;
convertUint256BE(tmpContent.txContent.chainID.value,
tmpContent.txContent.chainID.length,
&chainID);
tostring256(&chainID, 10, displayBuffer, sizeof(displayBuffer));
strncpy(strings.common.chainID, displayBuffer, sizeof(strings.common.chainID));
} else {
PRINTF("Txtype `%u` not supported while generating chainID\n", txContext.txType);
return;
}
}
bool no_consent = false;
no_consent = called_from_swap;

View File

@@ -8,7 +8,7 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
uint8_t signatureLength;
cx_ecfp_private_key_t privateKey;
uint32_t tx = 0;
uint32_t v = getV(&tmpContent.txContent);
uint32_t v = u32_from_BE(tmpContent.txContent.v, tmpContent.txContent.vLength, true);
io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(CX_CURVE_256K1,
tmpCtx.transactionContext.bip32Path,

View File

@@ -1,5 +1,7 @@
#include "shared_context.h"
#include "ui_callbacks.h"
#include "chainConfig.h"
#include "utils.h"
// clang-format off
UX_STEP_NOCB(
@@ -85,7 +87,7 @@ UX_FLOW(ux_confirm_parameter_flow,
//////////////////////////////////////////////////////////////////////
// clang-format off
UX_STEP_NOCB(ux_approval_tx_1_step,
UX_STEP_NOCB(ux_approval_review_step,
pnn,
{
&C_icon_eye,
@@ -93,28 +95,35 @@ UX_STEP_NOCB(ux_approval_tx_1_step,
"transaction",
});
UX_STEP_NOCB(
ux_approval_tx_2_step,
ux_approval_amount_step,
bnnn_paging,
{
.title = "Amount",
.text = strings.common.fullAmount
});
UX_STEP_NOCB(
ux_approval_tx_3_step,
ux_approval_address_step,
bnnn_paging,
{
.title = "Address",
.text = strings.common.fullAddress,
});
UX_STEP_NOCB(
ux_approval_tx_4_step,
ux_approval_fees_step,
bnnn_paging,
{
.title = "Max Fees",
.text = strings.common.maxFee,
});
UX_STEP_NOCB(
ux_approval_chainid_step,
bnnn_paging,
{
.title = "Chain ID",
.text = strings.common.chainID,
});
UX_STEP_CB(
ux_approval_tx_5_step,
ux_approval_accept_step,
pbb,
io_seproxyhal_touch_tx_ok(NULL),
{
@@ -123,7 +132,7 @@ UX_STEP_CB(
"and send",
});
UX_STEP_CB(
ux_approval_tx_6_step,
ux_approval_reject_step,
pb,
io_seproxyhal_touch_tx_cancel(NULL),
{
@@ -132,14 +141,14 @@ UX_STEP_CB(
});
UX_STEP_NOCB(
ux_approval_tx_display_nonce_step,
ux_approval_nonce_step,
bnnn_paging,
{
.title = "Nonce",
.text = strings.common.nonce,
});
UX_STEP_NOCB(ux_approval_tx_data_warning_step,
UX_STEP_NOCB(ux_approval_data_warning_step,
pbb,
{
&C_icon_warning,
@@ -148,22 +157,36 @@ UX_STEP_NOCB(ux_approval_tx_data_warning_step,
});
// clang-format on
const ux_flow_step_t *ux_approval_tx_flow_[9];
const ux_flow_step_t *ux_approval_tx_flow_[10];
void ux_approve_tx(bool dataPresent) {
int step = 0;
ux_approval_tx_flow_[step++] = &ux_approval_tx_1_step;
ux_approval_tx_flow_[step++] = &ux_approval_review_step;
if (dataPresent && !N_storage.contractDetails) {
ux_approval_tx_flow_[step++] = &ux_approval_tx_data_warning_step;
ux_approval_tx_flow_[step++] = &ux_approval_data_warning_step;
}
ux_approval_tx_flow_[step++] = &ux_approval_tx_2_step;
ux_approval_tx_flow_[step++] = &ux_approval_tx_3_step;
ux_approval_tx_flow_[step++] = &ux_approval_amount_step;
ux_approval_tx_flow_[step++] = &ux_approval_address_step;
if (N_storage.displayNonce) {
ux_approval_tx_flow_[step++] = &ux_approval_tx_display_nonce_step;
ux_approval_tx_flow_[step++] = &ux_approval_nonce_step;
}
ux_approval_tx_flow_[step++] = &ux_approval_tx_4_step;
ux_approval_tx_flow_[step++] = &ux_approval_tx_5_step;
ux_approval_tx_flow_[step++] = &ux_approval_tx_6_step;
uint32_t id;
if (txContext.txType == LEGACY) {
id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
} else if (txContext.txType == EIP2930) {
id =
u32_from_BE(txContext.content->chainID.value, txContext.content->chainID.length, false);
} else {
PRINTF("TxType `%u` not supported while preparing to approve tx\n", txContext.txType);
THROW(0x6501);
}
if (id != ETHEREUM_MAINNET_CHAINID) {
ux_approval_tx_flow_[step++] = &ux_approval_chainid_step;
}
ux_approval_tx_flow_[step++] = &ux_approval_fees_step;
ux_approval_tx_flow_[step++] = &ux_approval_accept_step;
ux_approval_tx_flow_[step++] = &ux_approval_reject_step;
ux_approval_tx_flow_[step++] = FLOW_END_STEP;
ux_flow_init(0, ux_approval_tx_flow_, NULL);