Merge pull request #276 from LedgerHQ/apr/bugfix/nft_security_review

NFT feature security review
This commit is contained in:
apaillier-ledger
2022-03-14 14:36:17 +01:00
committed by GitHub
74 changed files with 236 additions and 228 deletions

View File

@@ -1,3 +1,6 @@
#ifndef _APDU_CONSTANTS_H_
#define _APDU_CONSTANTS_H_
#include "shared_context.h"
#define APP_FLAG_DATA_ALLOWED 0x01
@@ -156,3 +159,5 @@ void handleStarkwareUnsafeSign(uint8_t p1,
unsigned int *tx);
#endif
#endif // _APDU_CONSTANTS_H_

View File

@@ -69,4 +69,4 @@ typedef struct chain_config_s {
#define ETHEREUM_MAINNET_CHAINID 1
#endif /* _CHAIN_CONFIG_H_ */
#endif // _CHAIN_CONFIG_H_

View File

@@ -48,14 +48,14 @@ void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
memset((uint8_t *) queryContractUI, 0, sizeof(ethQueryContractUI_t));
// If no extra information was found, set the pointer to NULL
if (allzeroes(&tmpCtx.transactionContext.extraInfo[1], sizeof(union extraInfo_t))) {
if (NO_EXTRA_INFO(tmpCtx, 1)) {
queryContractUI->item1 = NULL;
} else {
queryContractUI->item1 = &tmpCtx.transactionContext.extraInfo[1];
}
// If no extra information was found, set the pointer to NULL
if (allzeroes(&tmpCtx.transactionContext.extraInfo[0], sizeof(union extraInfo_t))) {
if (NO_EXTRA_INFO(tmpCtx, 0)) {
queryContractUI->item2 = NULL;
} else {
queryContractUI->item2 = &tmpCtx.transactionContext.extraInfo[0];

View File

@@ -1,7 +1,11 @@
#ifndef __ETH_PLUGIN_HANDLER_H__
#ifndef _ETH_PLUGIN_HANDLER_H_
#define _ETH_PLUGIN_HANDLER_H_
#include "eth_plugin_interface.h"
#define NO_EXTRA_INFO(ctx, idx) \
(allzeroes(&(ctx.transactionContext.extraInfo[idx]), sizeof(extraInfo_t)))
void eth_plugin_prepare_init(ethPluginInitContract_t *init, uint8_t *selector, uint32_t dataSize);
void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *provideParameter,
uint8_t *parameter,
@@ -27,4 +31,4 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter);
void plugin_ui_start(void);
#endif
#endif // _ETH_PLUGIN_HANDLER_H_

View File

@@ -1,6 +1,5 @@
#ifndef __ETH_PLUGIN_INTERFACE_H__
#define __ETH_PLUGIN_INTERFACE_H__
#ifndef _ETH_PLUGIN_INTERFACE_H_
#define _ETH_PLUGIN_INTERFACE_H_
#include "os.h"
#include "cx.h"
@@ -179,4 +178,4 @@ typedef struct ethQueryContractUI_t {
} ethQueryContractUI_t;
#endif
#endif // _ETH_PLUGIN_INTERFACE_H_

View File

@@ -1,3 +1,4 @@
#include <string.h>
#include "eth_plugin_internal.h"
bool erc20_plugin_available_check(void);

View File

@@ -1,5 +1,8 @@
#ifndef __ETH_PLUGIN_INTERNAL_H__
#ifndef _ETH_PLUGIN_INTERNAL_H_
#define _ETH_PLUGIN_INTERNAL_H_
#include <stdint.h>
#include <stdbool.h>
#include "eth_plugin_interface.h"
#define SELECTOR_SIZE 4
@@ -45,4 +48,4 @@ extern const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS];
extern internalEthPlugin_t const INTERNAL_ETH_PLUGINS[];
#endif
#endif // _ETH_PLUGIN_INTERNAL_H_

View File

@@ -6,11 +6,6 @@
#define ZERO(x) memset(&x, 0, sizeof(x))
static int os_strcmp(const char* s1, const char* s2) {
size_t size = strlen(s1) + 1;
return memcmp(s1, s2, size);
}
int handle_check_address(check_address_parameters_t* params, chain_config_t* chain_config) {
PRINTF("Params on the address %d\n", (unsigned int) params);
PRINTF("Address to check %s\n", params->address_to_check);
@@ -69,7 +64,7 @@ int handle_check_address(check_address_parameters_t* params, chain_config_t* cha
offset_0x = 2;
}
if (os_strcmp(locals_union1.address, params->address_to_check + offset_0x) != 0) {
if (strcmp(locals_union1.address, params->address_to_check + offset_0x) != 0) {
PRINTF("Addresses don't match\n");
return 0;
}

View File

@@ -1,6 +1,6 @@
#include "handle_swap_sign_transaction.h"
#include "usbd_core.h"
#include "os_io_seproxyhal.h"
#include "ux.h"
#include "handle_swap_sign_transaction.h"
#include "shared_context.h"
#include "utils.h"
@@ -79,4 +79,4 @@ void handle_swap_sign_transaction(chain_config_t* config) {
BLE_power(1, "Nano X");
#endif // HAVE_BLE
app_main();
}
}

View File

@@ -386,7 +386,8 @@ extraInfo_t *getKnownToken(uint8_t *contractAddress) {
}
}
#endif
//
// Works for ERC-20 & NFT tokens since both structs in the union have the
// contract address aligned
for (uint8_t i = 0; i < MAX_ITEMS; i++) {
currentItem = (union extraInfo_t *) &tmpCtx.transactionContext.extraInfo[i].token;
if (tmpCtx.transactionContext.tokenSet[i] &&
@@ -396,15 +397,6 @@ extraInfo_t *getKnownToken(uint8_t *contractAddress) {
}
}
for (uint8_t i = 0; i < MAX_ITEMS; i++) {
currentItem = (union extraInfo_t *) &tmpCtx.transactionContext.extraInfo[i].token;
if (tmpCtx.transactionContext.tokenSet[i] &&
(memcmp(currentItem->nft.contractAddress, contractAddress, ADDRESS_LENGTH) == 0)) {
PRINTF("Token found at index %d\n", i);
return currentItem;
}
}
return NULL;
}

View File

@@ -1,14 +1,14 @@
#include "tokens.h"
#ifndef _NFT_H_
#define _NFT_H_
// An `nftInfo_t` must be the same size as a `tokenDefinition_t`. This is because both will be held
// in a `extraInfo_t` which is a union of a `nftInfo_t` and a `tokenDefinition_t`. By having both
// struct the same size, we know they will be aligned, which facilitates accessing the items.
#include <stdint.h>
// We defined the collection name max length to be the size of a `tokenDefinition_t` and remove the
// `ADDRESS_LENGTH` which corresponds to `sizeof(contractAddress`).
#define COLLECTION_NAME_MAX_LEN (sizeof(tokenDefinition_t) - ADDRESS_LENGTH)
#define COLLECTION_NAME_MAX_LEN 70
#define NO_NFT_METADATA (NO_EXTRA_INFO(tmpCtx, 1))
typedef struct nftInfo_t {
char collectionName[COLLECTION_NAME_MAX_LEN];
char contractAddress[ADDRESS_LENGTH];
} nftInfo_t;
uint8_t contractAddress[ADDRESS_LENGTH]; // must be first item
char collectionName[COLLECTION_NAME_MAX_LEN + 1];
} nftInfo_t;
#endif // _NFT_H_

View File

@@ -1,5 +1,5 @@
#ifndef __POORSTREAM_H__
#define __POORSTREAM_H__
#ifndef _POORSTREAM_H_
#define _POORSTREAM_H_
#include <stdbool.h>
#include <stdint.h>
@@ -18,4 +18,4 @@ void poorstream_init(poorstream_t *stream, uint8_t *buffer);
void poorstream_flush(poorstream_t *stream);
void poorstream_write_bits(poorstream_t *stream, uint64_t bits, uint32_t num_bits);
#endif
#endif // _POORSTREAM_H_

View File

@@ -1,16 +1,9 @@
#ifndef __SHARED_CONTEXT_H__
#define __SHARED_CONTEXT_H__
#ifndef _SHARED_CONTEXT_H_
#define _SHARED_CONTEXT_H_
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "os.h"
#include "cx.h"
#include "os_io_seproxyhal.h"
#include "ethUstream.h"
#include "uint256.h"
#include "tokens.h"
#include "chainConfig.h"
#include "nft.h"
@@ -221,4 +214,4 @@ extern uint32_t eth2WithdrawalIndex;
void reset_app_context(void);
#endif // __SHARED_CONTEXT_H__
#endif // _SHARED_CONTEXT_H_

View File

@@ -1,5 +1,5 @@
#ifndef __STARK_CRYPTO_H__
#define __STARK_CRYPTO_H__
#ifndef _STARK_CRYPTO_H_
#define _STARK_CRYPTO_H_
#include <stdbool.h>
#include <stdint.h>
@@ -18,4 +18,4 @@ void pedersen(FieldElement res, /* out */
FieldElement a,
FieldElement b);
#endif
#endif // _STARK_CRYPTO_H_

View File

@@ -1,5 +1,5 @@
#ifndef __STARK_UTILS_H__
#define __STARK_UTILS_H__
#ifndef _STARK_UTILS_H_
#define _STARK_UTILS_H_
#include <stdbool.h>
#include <stdint.h>
@@ -32,4 +32,4 @@ int stark_sign(uint8_t *signature, /* out */
FieldElement msg,
FieldElement condition);
#endif
#endif // _STARK_UTILS_H_

View File

@@ -1,5 +1,5 @@
#ifndef SWAP_LIB_CALLS
#define SWAP_LIB_CALLS
#ifndef _SWAP_LIB_CALLS_H_
#define _SWAP_LIB_CALLS_H_
#include "stdbool.h"
@@ -50,4 +50,4 @@ typedef struct create_transaction_parameters_s {
char* destination_address_extra_id;
} create_transaction_parameters_t;
#endif
#endif // _SWAP_LIB_CALLS_H_

View File

@@ -25,14 +25,11 @@
#define MAX_ITEMS 2
typedef struct tokenDefinition_t {
uint8_t address[ADDRESS_LENGTH]; // must be first item
#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR
uint8_t contractName[ADDRESS_LENGTH];
#endif
uint8_t address[ADDRESS_LENGTH];
char ticker[MAX_TICKER_LEN];
char nft_pad[20]; // Adding some padding because the `nftInfo_t` is based on the size of a
// `tokenDefinition_t`. By adding some padding here we give more space to the
// collection name in the `nftInfo_t`. See `nftInfo_t` for more information.
uint8_t decimals;
} tokenDefinition_t;
@@ -46,25 +43,23 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
#ifndef HAVE_TOKENS_LIST
static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
#ifndef LEDGER_TEST_PUBLIC_KEY
static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
// production key 2019-01-11 03:07PM (erc20signer)
0x04, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9,
0x7c, 0x0b, 0x68, 0xcd, 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e,
0x7b, 0x30, 0xfe, 0x4e, 0x8c, 0xc7, 0x6b, 0x14, 0x89, 0x15, 0x0c, 0x21, 0x51,
0x4e, 0xbf, 0x44, 0x0f, 0xf5, 0xde, 0xa5, 0x39, 0x3d, 0x83, 0xde, 0x53, 0x58,
0xcd, 0x09, 0x8f, 0xce, 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83};
0x04, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x7c,
0x0b, 0x68, 0xcd, 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e, 0x7b, 0x30,
0xfe, 0x4e, 0x8c, 0xc7, 0x6b, 0x14, 0x89, 0x15, 0x0c, 0x21, 0x51, 0x4e, 0xbf, 0x44,
0x0f, 0xf5, 0xde, 0xa5, 0x39, 0x3d, 0x83, 0xde, 0x53, 0x58, 0xcd, 0x09, 0x8f, 0xce,
0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83
#else
static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
// test key 2019-01-11 03:07PM (erc20signer)
0x04, 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1,
0x0f, 0xe4, 0xc3, 0x04, 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e,
0x84, 0xf4, 0x50, 0x91, 0x42, 0x9b, 0x52, 0x20, 0xaf, 0x9e, 0x35, 0xc0, 0xb2,
0xd9, 0x28, 0x93, 0x80, 0x13, 0x73, 0x07, 0xde, 0x4d, 0xd1, 0xd4, 0x18, 0x42,
0x8c, 0xf2, 0x1a, 0x93, 0xb3, 0x35, 0x61, 0xbb, 0x09, 0xd8, 0x8f, 0xe5, 0x79,
};
0x04, 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1, 0x0f,
0xe4, 0xc3, 0x04, 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e, 0x84, 0xf4,
0x50, 0x91, 0x42, 0x9b, 0x52, 0x20, 0xaf, 0x9e, 0x35, 0xc0, 0xb2, 0xd9, 0x28, 0x93,
0x80, 0x13, 0x73, 0x07, 0xde, 0x4d, 0xd1, 0xd4, 0x18, 0x42, 0x8c, 0xf2, 0x1a, 0x93,
0xb3, 0x35, 0x61, 0xbb, 0x09, 0xd8, 0x8f, 0xe5, 0x79
#endif
};
#else
@@ -146,4 +141,4 @@ extern tokenDefinition_t const TOKENS_SHYFT[NUM_TOKENS_SHYFT];
#endif /* HAVE_TOKENS_LIST */
#endif /* _TOKENS_H_ */
#endif // _TOKENS_H_

View File

@@ -1,3 +1,6 @@
#ifndef _UI_CALLBACKS_H_
#define _UI_CALLBACKS_H_
#include "shared_context.h"
#include "ux.h"
@@ -22,3 +25,5 @@ void io_seproxyhal_send_status(uint32_t sw);
void format_signature_out(const uint8_t *signature);
void finalizeParsing(bool direct);
extraInfo_t *getKnownToken(uint8_t *contractAddress);
#endif // _UI_CALLBACKS_H_

View File

@@ -1,3 +1,6 @@
#ifndef _UI_FLOW_H_
#define _UI_FLOW_H_
#include "shared_context.h"
#include "os_io_seproxyhal.h"
@@ -52,3 +55,5 @@ extern const ux_flow_step_t* const ux_approval_starkware_verify_escape_flow[];
extern const ux_flow_step_t* const ux_stark_unsafe_sign_flow[];
#endif
#endif // _UI_FLOW_H_

View File

@@ -41,4 +41,4 @@ void amountToString(const uint8_t* amount,
bool parse_swap_config(uint8_t* config, uint8_t config_len, char* ticker, uint8_t* decimals);
#endif /* _UTILS_H_ */
#endif // _UTILS_H_

View File

@@ -164,4 +164,4 @@ parserStatus_e continueTx(txContext_t *context);
void copyTxData(txContext_t *context, uint8_t *out, uint32_t length);
uint8_t readTxByte(txContext_t *context);
#endif /* _ETHUSTREAM_H_ */
#endif // _ETHUSTREAM_H_

View File

@@ -237,12 +237,6 @@ void getEthDisplayableAddress(uint8_t *in,
getEthAddressStringFromBinary(in, out + 2, sha3, chainId);
}
uint8_t *getNftContractAddress(const ethQueryContractUI_t *const msg) {
// In case of no PROVIDE_NFT_INFO, we already have the address from the SET_PLUGIN
return ((msg->item1) ? ((uint8_t *) msg->item1->nft.contractAddress)
: msg->pluginSharedRO->txContent->destination);
}
bool adjustDecimals(const char *src,
size_t srcLength,
char *target,

View File

@@ -22,7 +22,6 @@
#include "cx.h"
#include "chainConfig.h"
#include "eth_plugin_interface.h"
/**
* @brief Decode an RLP encoded field - see
@@ -59,8 +58,6 @@ void getEthDisplayableAddress(uint8_t *in,
cx_sha3_t *sha3,
uint64_t chainId);
uint8_t *getNftContractAddress(const ethQueryContractUI_t *const msg);
bool adjustDecimals(const char *src,
size_t srcLength,
char *target,
@@ -87,4 +84,4 @@ static __attribute__((no_instrument_function)) inline int ismaxint(uint8_t *buf,
static const char HEXDIGITS[] = "0123456789abcdef";
#endif /* _ETHUTILS_H_ */
#endif // _ETHUTILS_H_

View File

@@ -1,3 +1,6 @@
#ifndef _NETWORK_H_
#define _NETWORK_H_
#include <stdint.h>
#include "tokens.h"
#include "shared_context.h"
@@ -17,4 +20,6 @@ const network_info_t *get_network(void);
// Returns a pointer to the network name, or NULL if there is none.
const char *get_network_name(void);
// Returns a pointer to the network ticker, or chainConfig->coinName if there is none.
const char *get_network_ticker(void);
const char *get_network_ticker(void);
#endif // _NETWORK_H_

View File

@@ -73,4 +73,4 @@ void divmod256(uint256_t *l, uint256_t *r, uint256_t *div, uint256_t *mod);
bool tostring128(uint128_t *number, uint32_t base, char *out, uint32_t outLength);
bool tostring256(uint256_t *number, uint32_t base, char *out, uint32_t outLength);
#endif /* _UINT256_H_ */
#endif // _UINT256_H_

View File

@@ -1,3 +1,8 @@
#ifndef _GET_ETH2_PUB_KEY_H_
#define _GET_ETH2_PUB_KEY_H_
#include "shared_context.h"
uint32_t set_result_get_eth2_publicKey(void);
#endif // _GET_ETH2_PUB_KEY_H_

View File

@@ -1,5 +1,6 @@
#ifdef HAVE_ETH2
#include <string.h>
#include "shared_context.h"
uint32_t set_result_get_eth2_publicKey() {
@@ -9,4 +10,4 @@ uint32_t set_result_get_eth2_publicKey() {
return tx;
}
#endif
#endif // HAVE_ETH2

View File

@@ -1,3 +1,8 @@
#ifndef _GET_PUB_KEY_H_
#define _GET_PUB_KEY_H_
#include "shared_context.h"
uint32_t set_result_get_publicKey(void);
#endif // _GET_PUB_KEY_H_

View File

@@ -1,3 +1,4 @@
#include <string.h>
#include "shared_context.h"
uint32_t set_result_get_publicKey() {

View File

@@ -34,7 +34,6 @@ static const uint8_t LEDGER_NFT_METADATA_PUBLIC_KEY[] = {
0x7d, 0x0b, 0x46, 0x9a, 0x53, 0x11, 0xee, 0x6a, 0x1a, 0xcd, 0x1d, 0xa5, 0xaa, 0xb0,
0xf5, 0xc6, 0xdf, 0x13, 0x15, 0x8d, 0x28, 0xcc, 0x12, 0xd1, 0xdd, 0xa6, 0xec, 0xe9,
0x46, 0xb8, 0x9d, 0x5c, 0x05, 0x49, 0x92, 0x59, 0xc4
#else
0x04, 0x98, 0x8d, 0xa6, 0xb2, 0x46, 0xf2, 0x8e, 0x77, 0xc1, 0xba, 0xb6, 0x75, 0xcb,
0x2a, 0x27, 0x44, 0xf7, 0xf5, 0xce, 0xc5, 0x6a, 0xe6, 0xe0, 0x32, 0x23, 0x33, 0x7b,
@@ -64,8 +63,12 @@ void handleProvideNFTInformation(uint8_t p1,
UNUSED(flags);
uint8_t hash[INT256_LENGTH];
cx_ecfp_public_key_t nftKey;
PRINTF("In handle provide NFTInformation");
PRINTF("In handle provide NFTInformation\n");
if ((pluginType != ERC721) && (pluginType != ERC1155)) {
PRINTF("NFT metadata provided without proper plugin loaded!\n");
THROW(0x6985);
}
tmpCtx.transactionContext.currentItemIndex =
(tmpCtx.transactionContext.currentItemIndex + 1) % MAX_ITEMS;
nftInfo_t *nft =
@@ -117,10 +120,10 @@ void handleProvideNFTInformation(uint8_t p1,
THROW(0x6A80);
}
if (collectionNameLength + 1 > sizeof(nft->collectionName)) {
if (collectionNameLength > COLLECTION_NAME_MAX_LEN) {
PRINTF("CollectionName too big: expected max %d, got %d\n",
sizeof(nft->collectionName),
collectionNameLength + 1);
COLLECTION_NAME_MAX_LEN,
collectionNameLength);
THROW(0x6A80);
}

View File

@@ -1,3 +1,6 @@
#ifndef _SET_WITHDRAWAL_INDEX_H_
#define _SET_WITHDRAWAL_INDEX_H_
#include "stdint.h"
void handleSetEth2WithdrawalIndex(uint8_t p1,
@@ -5,4 +8,6 @@ void handleSetEth2WithdrawalIndex(uint8_t p1,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
unsigned int *tx);
#endif // _SET_WITHDRAWAL_INDEX_H_

View File

@@ -1,3 +1,4 @@
#include "os_io_seproxyhal.h"
#include "shared_context.h"
#include "ui_callbacks.h"

View File

@@ -1,3 +1,4 @@
#include "os_io_seproxyhal.h"
#include "shared_context.h"
#include "ui_callbacks.h"

View File

@@ -1,3 +1,6 @@
#ifndef _SIGN_TX_H_
#define _SIGN_TX_H_
#include "shared_context.h"
typedef enum {
@@ -12,3 +15,5 @@ void finalizeParsing(bool direct);
void prepareFeeDisplay();
void prepareNetworkDisplay();
void ux_approve_tx(bool fromPlugin);
#endif // _SIGN_TX_H_

View File

@@ -1,3 +1,4 @@
#include "os_io_seproxyhal.h"
#include "shared_context.h"
#include "utils.h"
#include "ui_callbacks.h"

View File

@@ -1,5 +1,8 @@
#pragma once
#ifndef _UI_PLUGIN_H_
#define _UI_PLUGIN_H_
void plugin_ui_get_id();
void plugin_ui_get_item();
void display_next_plugin_item(bool entering);
void display_next_plugin_item(bool entering);
#endif // _UI_PLUGIN_H_

View File

@@ -1,3 +1,8 @@
#ifndef _STARK_GET_PUB_KEY_H_
#define _STARK_GET_PUB_KEY_H_
#include "shared_context.h"
uint32_t set_result_get_stark_publicKey(void);
#endif // _STARK_GET_PUB_KEY_H_

View File

@@ -1,5 +1,6 @@
#ifdef HAVE_STARKWARE
#include <string.h>
#include "shared_context.h"
#include "feature_stark_getPublicKey.h"
@@ -10,4 +11,4 @@ uint32_t set_result_get_stark_publicKey() {
return tx;
}
#endif
#endif // HAVE_STARKWARE

View File

@@ -1,5 +1,6 @@
#ifdef HAVE_STARKWARE
#include "os_io_seproxyhal.h"
#include "shared_context.h"
#include "stark_utils.h"
#include "ui_callbacks.h"
@@ -32,4 +33,4 @@ unsigned int io_seproxyhal_touch_stark_ok(__attribute__((unused)) const bagl_ele
return 0; // do not redraw the widget
}
#endif
#endif // HAVE_STARKWARE

View File

@@ -1,5 +1,6 @@
#ifdef HAVE_STARKWARE
#include "os_io_seproxyhal.h"
#include "shared_context.h"
#include "stark_utils.h"
#include "ui_callbacks.h"
@@ -38,4 +39,4 @@ unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(__attribute__((unused))
return 0; // do not redraw the widget
}
#endif
#endif // HAVE_STARKWARE

View File

@@ -1,13 +1,16 @@
#ifdef HAVE_NFT_SUPPORT
#include <string.h>
#include "erc1155_plugin.h"
#include "eth_plugin_internal.h"
#include "ethUtils.h"
#include "eth_plugin_handler.h"
static const uint8_t ERC1155_APPROVE_FOR_ALL_SELECTOR[SELECTOR_SIZE] = {0xa2, 0x2c, 0xb4, 0x65};
static const uint8_t ERC1155_SAFE_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0xf2, 0x42, 0x43, 0x2a};
static const uint8_t ERC1155_SAFE_BATCH_TRANSFER[SELECTOR_SIZE] = {0x2e, 0xb2, 0xc2, 0xd6};
const uint8_t *const ERC1155_SELECTORS[NUM_ERC1155_SELECTORS] = {
const uint8_t *const ERC1155_SELECTORS[SELECTORS_COUNT] = {
ERC1155_APPROVE_FOR_ALL_SELECTOR,
ERC1155_SAFE_TRANSFER_SELECTOR,
ERC1155_SAFE_BATCH_TRANSFER,
@@ -17,8 +20,13 @@ static void handle_init_contract(void *parameters) {
ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
erc1155_context_t *context = (erc1155_context_t *) msg->pluginContext;
if (NO_NFT_METADATA) {
PRINTF("No NFT metadata when trying to sign!\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}
uint8_t i;
for (i = 0; i < NUM_ERC1155_SELECTORS; i++) {
for (i = 0; i < SELECTORS_COUNT; i++) {
if (memcmp((uint8_t *) PIC(ERC1155_SELECTORS[i]), msg->selector, SELECTOR_SIZE) == 0) {
context->selectorIndex = i;
break;
@@ -26,7 +34,7 @@ static void handle_init_contract(void *parameters) {
}
// No selector found.
if (i == NUM_ERC1155_SELECTORS) {
if (i == SELECTORS_COUNT) {
PRINTF("Unknown erc1155 selector %.*H\n", SELECTOR_SIZE, msg->selector);
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
return;

View File

@@ -1,22 +1,21 @@
#ifndef _ERC1155_PLUGIN_H_
#define _ERC1155_PLUGIN_H_
#ifdef HAVE_NFT_SUPPORT
#pragma once
#include <string.h>
#include "eth_plugin_handler.h"
#include "shared_context.h"
#include "ethUtils.h"
#include "utils.h"
#include <stdbool.h>
#include <stdint.h>
#include "ethUstream.h"
#include "uint256.h"
#include "nft.h"
// Internal plugin for EIP 1155: https://eips.ethereum.org/EIPS/eip-1155
#define NUM_ERC1155_SELECTORS 3
typedef enum {
SET_APPROVAL_FOR_ALL,
SAFE_TRANSFER,
SAFE_BATCH_TRANSFER,
SELECTORS_COUNT
} erc1155_selector_t;
typedef enum {
@@ -53,3 +52,5 @@ void handle_provide_parameter_1155(void *parameters);
void handle_query_contract_ui_1155(void *parameters);
#endif // HAVE_NFT_SUPPORT
#endif // _ERC1155_PLUGIN_H_

View File

@@ -1,7 +1,10 @@
#ifdef HAVE_NFT_SUPPORT
#include <string.h>
#include "erc1155_plugin.h"
#include "eth_plugin_internal.h"
#include "utils.h"
#include "ethUtils.h"
static void handle_safe_transfer(ethPluginProvideParameter_t *msg, erc1155_context_t *context) {
uint8_t new_value[INT256_LENGTH];

View File

@@ -1,6 +1,10 @@
#ifdef HAVE_NFT_SUPPORT
#include <string.h>
#include "erc1155_plugin.h"
#include "eth_plugin_interface.h"
#include "ethUtils.h"
#include "utils.h"
static void set_approval_for_all_ui(ethQueryContractUI_t *msg, erc1155_context_t *context) {
switch (msg->screenIndex) {
@@ -18,15 +22,11 @@ static void set_approval_for_all_ui(ethQueryContractUI_t *msg, erc1155_context_t
break;
case 1:
strlcpy(msg->title, "To Manage ALL", msg->titleLength);
if (msg->item1) {
strlcpy(msg->msg, (const char *) &msg->item1->nft.collectionName, msg->msgLength);
} else {
strlcpy(msg->msg, "Not found", msg->msgLength);
}
strlcpy(msg->msg, msg->item1->nft.collectionName, msg->msgLength);
break;
case 2:
strlcpy(msg->title, "NFT Address", msg->titleLength);
getEthDisplayableAddress(getNftContractAddress(msg),
getEthDisplayableAddress(msg->item1->nft.contractAddress,
msg->msg,
msg->msgLength,
&global_sha3,
@@ -51,15 +51,11 @@ static void set_transfer_ui(ethQueryContractUI_t *msg, erc1155_context_t *contex
break;
case 1:
strlcpy(msg->title, "Collection Name", msg->titleLength);
if (msg->item1) {
strlcpy(msg->msg, (const char *) &msg->item1->nft.collectionName, msg->msgLength);
} else {
strlcpy(msg->msg, "Not Found", msg->msgLength);
}
strlcpy(msg->msg, msg->item1->nft.collectionName, msg->msgLength);
break;
case 2:
strlcpy(msg->title, "NFT Address", msg->titleLength);
getEthDisplayableAddress(getNftContractAddress(msg),
getEthDisplayableAddress(msg->item1->nft.contractAddress,
msg->msg,
msg->msgLength,
&global_sha3,
@@ -97,15 +93,11 @@ static void set_batch_transfer_ui(ethQueryContractUI_t *msg, erc1155_context_t *
break;
case 1:
strlcpy(msg->title, "Collection Name", msg->titleLength);
if (msg->item1) {
strlcpy(msg->msg, (const char *) &msg->item1->nft.collectionName, msg->msgLength);
} else {
strlcpy(msg->msg, "Not Found", msg->msgLength);
}
strlcpy(msg->msg, msg->item1->nft.collectionName, msg->msgLength);
break;
case 2:
strlcpy(msg->title, "NFT Address", msg->titleLength);
getEthDisplayableAddress(getNftContractAddress(msg),
getEthDisplayableAddress(msg->item1->nft.contractAddress,
msg->msg,
msg->msgLength,
&global_sha3,

View File

@@ -1,7 +1,11 @@
#ifdef HAVE_NFT_SUPPORT
#include <string.h>
#include "erc721_plugin.h"
#include "eth_plugin_internal.h"
#include "eth_plugin_interface.h"
#include "ethUtils.h"
#include "eth_plugin_handler.h"
static const uint8_t ERC721_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3};
static const uint8_t ERC721_APPROVE_FOR_ALL_SELECTOR[SELECTOR_SIZE] = {0xa2, 0x2c, 0xb4, 0x65};
@@ -9,7 +13,7 @@ static const uint8_t ERC721_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0x23, 0xb8, 0x72
static const uint8_t ERC721_SAFE_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0x42, 0x84, 0x2e, 0x0e};
static const uint8_t ERC721_SAFE_TRANSFER_DATA_SELECTOR[SELECTOR_SIZE] = {0xb8, 0x8d, 0x4f, 0xde};
const uint8_t *const ERC721_SELECTORS[NUM_ERC721_SELECTORS] = {
const uint8_t *const ERC721_SELECTORS[SELECTORS_COUNT] = {
ERC721_APPROVE_SELECTOR,
ERC721_APPROVE_FOR_ALL_SELECTOR,
ERC721_TRANSFER_SELECTOR,
@@ -21,8 +25,13 @@ static void handle_init_contract(void *parameters) {
ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
erc721_context_t *context = (erc721_context_t *) msg->pluginContext;
if (NO_NFT_METADATA) {
PRINTF("No NFT metadata when trying to sign!\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}
uint8_t i;
for (i = 0; i < NUM_ERC721_SELECTORS; i++) {
for (i = 0; i < SELECTORS_COUNT; i++) {
if (memcmp((uint8_t *) PIC(ERC721_SELECTORS[i]), msg->selector, SELECTOR_SIZE) == 0) {
context->selectorIndex = i;
break;
@@ -30,7 +39,7 @@ static void handle_init_contract(void *parameters) {
}
// No selector found.
if (i == NUM_ERC721_SELECTORS) {
if (i == SELECTORS_COUNT) {
PRINTF("Unknown erc721 selector %.*H\n", SELECTOR_SIZE, msg->selector);
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
return;

View File

@@ -1,23 +1,22 @@
#ifndef _ERC721_PLUGIN_H_
#define _ERC721_PLUGIN_H_
#ifdef HAVE_NFT_SUPPORT
#pragma once
#include <string.h>
#include "eth_plugin_handler.h"
#include "shared_context.h"
#include "ethUtils.h"
#include "utils.h"
#include <stdbool.h>
#include <stdint.h>
#include "ethUstream.h"
#include "nft.h"
// Internal plugin for EIP 721: https://eips.ethereum.org/EIPS/eip-721
#define NUM_ERC721_SELECTORS 5
typedef enum {
APPROVE,
SET_APPROVAL_FOR_ALL,
TRANSFER,
SAFE_TRANSFER,
SAFE_TRANSFER_DATA,
SELECTORS_COUNT
} erc721_selector_t;
typedef enum {
@@ -44,3 +43,5 @@ void handle_provide_parameter_721(void *parameters);
void handle_query_contract_ui_721(void *parameters);
#endif // HAVE_NFT_SUPPORT
#endif // _ERC721_PLUGIN_H_

View File

@@ -1,6 +1,10 @@
#ifdef HAVE_NFT_SUPPORT
#include <string.h>
#include "erc721_plugin.h"
#include "eth_plugin_interface.h"
#include "ethUtils.h"
#include "utils.h"
static void set_approval_ui(ethQueryContractUI_t *msg, erc721_context_t *context) {
switch (msg->screenIndex) {
@@ -14,15 +18,11 @@ static void set_approval_ui(ethQueryContractUI_t *msg, erc721_context_t *context
break;
case 1:
strlcpy(msg->title, "To Manage Your", msg->titleLength);
if (msg->item1) {
strlcpy(msg->msg, (const char *) &msg->item1->nft.collectionName, msg->msgLength);
} else {
strlcpy(msg->msg, "Not Found", msg->msgLength);
}
strlcpy(msg->msg, msg->item1->nft.collectionName, msg->msgLength);
break;
case 2:
strlcpy(msg->title, "NFT Address", msg->titleLength);
getEthDisplayableAddress(getNftContractAddress(msg),
getEthDisplayableAddress(msg->item1->nft.contractAddress,
msg->msg,
msg->msgLength,
&global_sha3,
@@ -58,15 +58,11 @@ static void set_approval_for_all_ui(ethQueryContractUI_t *msg, erc721_context_t
break;
case 1:
strlcpy(msg->title, "To Manage ALL", msg->titleLength);
if (msg->item1) {
strlcpy(msg->msg, (const char *) &msg->item1->nft.collectionName, msg->msgLength);
} else {
strlcpy(msg->msg, "Not found", msg->msgLength);
}
strlcpy(msg->msg, msg->item1->nft.collectionName, msg->msgLength);
break;
case 2:
strlcpy(msg->title, "NFT Address", msg->titleLength);
getEthDisplayableAddress(getNftContractAddress(msg),
getEthDisplayableAddress(msg->item1->nft.contractAddress,
msg->msg,
msg->msgLength,
&global_sha3,
@@ -91,15 +87,11 @@ static void set_transfer_ui(ethQueryContractUI_t *msg, erc721_context_t *context
break;
case 1:
strlcpy(msg->title, "Collection Name", msg->titleLength);
if (msg->item1) {
strlcpy(msg->msg, (const char *) &msg->item1->nft.collectionName, msg->msgLength);
} else {
strlcpy(msg->msg, "Not Found", msg->msgLength);
}
strlcpy(msg->msg, msg->item1->nft.collectionName, msg->msgLength);
break;
case 2:
strlcpy(msg->title, "NFT Address", msg->titleLength);
getEthDisplayableAddress(getNftContractAddress(msg),
getEthDisplayableAddress(msg->item1->nft.contractAddress,
msg->msg,
msg->msgLength,
&global_sha3,

View File

@@ -1,4 +1,5 @@
#include <string.h>
#include "os_io_seproxyhal.h"
#include "eth_plugin_interface.h"
#include "shared_context.h" // TODO : rewrite as independant code
#include "eth_plugin_internal.h" // TODO : rewrite as independant code

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00000.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00001.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00002.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00004.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00005.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00006.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00007.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00008.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00009.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00010.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00011.png

View File

@@ -1 +0,0 @@
../nanox_erc1155_transfer/00012.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00000.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00001.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00002.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00004.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00005.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00006.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00007.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00008.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00009.png

View File

@@ -1 +0,0 @@
../nanox_erc721_transfer/00010.png

View File

@@ -26,29 +26,23 @@ const model = nano_models[1];
await sign_promise;
}));
test('[Nano ' + model.letter + '] Transfer ERC-1155 w/o PROVIDE_NFT_INFORMATION', zemu(model, async (sim, eth) => {
test('[Nano ' + model.letter + '] Transfer ERC-1155 w/o NFT metadata', zemu(model, async (sim, eth) => {
const current_screen = sim.getMainMenuSnapshot();
await send_apdu(eth.transport, set_plugin);
await send_apdu(eth.transport, sign_first);
let sign_promise = send_apdu(eth.transport, sign_more);
await waitForAppScreen(sim, current_screen);
await sim.navigateAndCompareSnapshots('.', model.name + '_erc1155_transfer_wo_info', [10, -1, 0]);
await sign_promise;
}));
test('[Nano ' + model.letter + '] Transfer ERC-1155 w/o SET_PLUGIN', zemu(model, async (sim, eth) => {
const current_screen = sim.getMainMenuSnapshot();
await send_apdu(eth.transport, provide_nft_info);
let sign_tx = send_apdu(eth.transport, sign_first);
await expect(sign_tx).rejects.toEqual(new TransportStatusError(0x6a80));
}));
test('[Nano ' + model.letter + '] Transfer ERC-1155 w/o plugin loaded', zemu(model, async (sim, eth) => {
const current_screen = sim.getMainMenuSnapshot();
let nft_info = send_apdu(eth.transport, provide_nft_info);
await expect(nft_info).rejects.toEqual(new TransportStatusError(0x6985));
}));
}
test('[Nano ' + model.letter + '] Batch transfer ERC-1155', zemu(model, async (sim, eth) => {
{
const set_plugin = apdu_as_string('e01600007401010745524331313535495f947276749ce646f68ac8c248420045cb7b5e2eb2c2d60000000000000001000147304502210087b35cefc53fd94e25404933eb0d5ff08f20ba655d181de3b24ff0099dc3317f02204a216aa9e0b84bef6e20fcb036bd49647bf0cab66732b99b49ec277ffb682aa1');
const provide_nft_info = apdu_as_string('e0140000820101194f70656e536561205368617265642053746f726566726f6e74495f947276749ce646f68ac8c248420045cb7b5e00000000000000010001473045022100c74cd613a27a9f4887210f5a3a0e12745e1ba0ab3a0d284cb6485d89c3cce4e602205a13e62a91164985cf58a838f8f531c0b91b980d206a5ba8df28270023ef93a3');
const sign_first = apdu_as_string('e004000096058000002c8000003c800000000000000000000000f9020b0e850d8cfd86008301617d94495f947276749ce646f68ac8c248420045cb7b5e80b901e42eb2c2d60000000000000000000000006cbcd73cd8e8a42844662f0a0e76d7f79afd933d000000000000000000000000c2907efcce4011c491bbeda8a0fa63ba7aab596c00000000000000000000000000000000000000000000');
@@ -56,16 +50,18 @@ test('[Nano ' + model.letter + '] Batch transfer ERC-1155', zemu(model, async (s
const sign_more_2 = apdu_as_string('e00480009689732473fcd0bbbe000000000000a30000000001abf06640f8ca8fc5e0ed471b10befcdf65a33e430000000000006a00000000640000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000010000');
const sign_more_3 = apdu_as_string('e00480006100000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000043078303000000000000000000000000000000000000000000000000000000000018080');
const current_screen = sim.getMainMenuSnapshot();
await send_apdu(eth.transport, set_plugin);
await send_apdu(eth.transport, provide_nft_info);
await send_apdu(eth.transport, sign_first);
await send_apdu(eth.transport, sign_more_1);
await send_apdu(eth.transport, sign_more_2);
let sign_promise = send_apdu(eth.transport, sign_more_3);
test('[Nano ' + model.letter + '] Batch transfer ERC-1155', zemu(model, async (sim, eth) => {
const current_screen = sim.getMainMenuSnapshot();
await send_apdu(eth.transport, set_plugin);
await send_apdu(eth.transport, provide_nft_info);
await send_apdu(eth.transport, sign_first);
await send_apdu(eth.transport, sign_more_1);
await send_apdu(eth.transport, sign_more_2);
let sign_promise = send_apdu(eth.transport, sign_more_3);
await waitForAppScreen(sim, current_screen);
await sim.navigateAndCompareSnapshots('.', model.name + '_erc1155_batch_transfer', [8, -1, 0]);
await waitForAppScreen(sim, current_screen);
await sim.navigateAndCompareSnapshots('.', model.name + '_erc1155_batch_transfer', [8, -1, 0]);
await sign_promise;
}));
await sign_promise;
}));
}

View File

@@ -25,22 +25,17 @@ test('[Nano ' + model.letter + '] Transfer ERC-721', zemu(model, async (sim, eth
await sign_promise;
}));
test('[Nano ' + model.letter + '] Transfer ERC-721 w/o NFT_PROVIDE_INFORMATION', zemu(model, async(sim, eth) => {
test('[Nano ' + model.letter + '] Transfer ERC-721 w/o NFT metadata', zemu(model, async(sim, eth) => {
const current_screen = sim.getMainMenuSnapshot();
await send_apdu(eth.transport, set_plugin);
await send_apdu(eth.transport, sign_first);
let sign_promise = send_apdu(eth.transport, sign_more);
await waitForAppScreen(sim, current_screen);
await sim.navigateAndCompareSnapshots('.', model.name + '_erc721_transfer_wo_info', [8, -1, 0]);
await sign_promise;
}));
test('[Nano ' + model.letter + '] Transfer ERC-721 w/o SET_PLUGIN', zemu(model, async (sim, eth) => {
const current_screen = sim.getMainMenuSnapshot();
await send_apdu(eth.transport, provide_nft_info);
let sign_tx = send_apdu(eth.transport, sign_first);
await expect(sign_tx).rejects.toEqual(new TransportStatusError(0x6a80));
}));
test('[Nano ' + model.letter + '] Transfer ERC-721 w/o plugin loaded', zemu(model, async (sim, eth) => {
const current_screen = sim.getMainMenuSnapshot();
let nft_info = send_apdu(eth.transport, provide_nft_info);
await expect(nft_info).rejects.toEqual(new TransportStatusError(0x6985));
}));