Skip to content

Commit

Permalink
Merge pull request cosmos#93 from cosmos/restriction_evm
Browse files Browse the repository at this point in the history
Restriction evm
  • Loading branch information
ftheirs committed Jun 13, 2023
2 parents 29acf41 + 4518d86 commit 99df548
Show file tree
Hide file tree
Showing 22 changed files with 161 additions and 49 deletions.
2 changes: 1 addition & 1 deletion app/Makefile.version
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ APPVERSION_M=2
# This is the `spec_version` field of `Runtime`
APPVERSION_N=35
# This is the patch version of this release
APPVERSION_P=9
APPVERSION_P=10
5 changes: 3 additions & 2 deletions app/src/addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
zxerr_t addr_getNumItems(uint8_t *num_items) {
zemu_log_stack("addr_getNumItems");
*num_items = 1;
if (app_mode_expert() || isEthPath) {

if (app_mode_expert() || encoding != BECH32_COSMOS ) {
zemu_log("num_items 2\n");
*num_items = 2;
} else {
Expand All @@ -47,7 +48,7 @@ zxerr_t addr_getItem(int8_t displayIdx,
ZEMU_LOGF(200, "[addr_getItem] pageCount %d\n", *pageCount)
return zxerr_ok;
case 1: {
if (!app_mode_expert() && !isEthPath) {
if (!app_mode_expert() && encoding == BECH32_COSMOS) {
return zxerr_no_data;
}

Expand Down
12 changes: 7 additions & 5 deletions app/src/apdu_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#include "parser_impl.h"
#include "view_internal.h"

bool isEthPath = false;
#include "chain_config.h"

static const char *msg_error1 = "Expert Mode";
static const char *msg_error2 = "Required";
Expand Down Expand Up @@ -74,8 +74,11 @@ static void extractHDPath(uint32_t rx, uint32_t offset) {
THROW(APDU_CODE_DATA_INVALID);
}

// Set EthPath flag
isEthPath = (hdPath[1] == HDPATH_ETH_1_DEFAULT) ? true : false;
encoding = checkChainConfig(hdPath[1], bech32_hrp, bech32_hrp_len);
if (encoding == UNSUPPORTED) {
ZEMU_LOGF(50, "Chain config not supported for: %s\n", bech32_hrp)
THROW(APDU_CODE_COMMAND_NOT_ALLOWED);
}

// Limit values unless the app is running in expert mode
if (!app_mode_expert()) {
Expand Down Expand Up @@ -124,7 +127,6 @@ __Z_INLINE void handleGetAddrSecp256K1(volatile uint32_t *flags, volatile uint32
extractHDPath(rx, OFFSET_DATA + 1 + len);

uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1];

zxerr_t zxerr = app_fill_address();
if (zxerr != zxerr_ok) {
*tx = 0;
Expand Down Expand Up @@ -158,7 +160,7 @@ __Z_INLINE void handleSign(volatile uint32_t *flags, volatile uint32_t *tx, uint
}
parser_tx_obj.tx_json.own_addr = (const char *) (G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SECP256K1);

if (isEthPath && !app_mode_expert()) {
if ((encoding != BECH32_COSMOS) && !app_mode_expert()) {
*flags |= IO_ASYNCH_REPLY;
view_custom_error_show(PIC(msg_error1),PIC(msg_error2));
THROW(APDU_CODE_DATA_INVALID);
Expand Down
51 changes: 51 additions & 0 deletions app/src/chain_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*******************************************************************************
* (c) 2018 - 2023 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#include "chain_config.h"
#include <zxmacros.h>

typedef struct {
const uint32_t path;
const char *hrp;
const address_encoding_e encoding;
} chain_config_t;

// To enable custom config for a new chain, just add a new entry in this array with path, hrp and encoding
static const chain_config_t chainConfig[] = {
// {118, cosmos, BECH32_COSMOS},
{60, "inj", BECH32_ETH},
};

static const uint32_t chainConfigLen = sizeof(chainConfig) / sizeof(chainConfig[0]);

address_encoding_e checkChainConfig(uint32_t path, const char* hrp, uint8_t hrpLen) {
// Always allowed for 118 (default Cosmos)
if (path == HDPATH_1_DEFAULT) {
return BECH32_COSMOS;
}

// Check special cases
for (uint32_t i = 0; i < chainConfigLen; i++) {
if (path == (0x80000000u | chainConfig[i].path)) {
const char* hrpPtr = (const char *) PIC(chainConfig[i].hrp);
const uint16_t hrpPtrLen = strlen(hrpPtr);
if (hrpPtrLen == hrpLen && memcmp(hrpPtr, hrp, hrpLen) == 0) {
return chainConfig[i].encoding;
}
}
}

return UNSUPPORTED;
}
30 changes: 30 additions & 0 deletions app/src/chain_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*******************************************************************************
* (c) 2018 - 2023 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <stdbool.h>
#include "coin.h"

address_encoding_e checkChainConfig(uint32_t path, const char* hrp, uint8_t hrpLen);

#ifdef __cplusplus
}
#endif
7 changes: 6 additions & 1 deletion app/src/coin.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ extern "C" {
#define PK_LEN_SECP256K1 33u
#define PK_LEN_SECP256K1_UNCOMPRESSED 65u

extern bool isEthPath;
typedef enum {
addr_secp256k1 = 0,
} address_kind_e;
Expand All @@ -42,6 +41,12 @@ typedef enum {
tx_textual
} tx_type_e;

typedef enum {
BECH32_COSMOS = 0,
BECH32_ETH,
UNSUPPORTED = 0xFF,
} address_encoding_e;

#define VIEW_ADDRESS_OFFSET_SECP256K1 PK_LEN_SECP256K1
#define VIEW_ADDRESS_LAST_PAGE_DEFAULT 0

Expand Down
51 changes: 35 additions & 16 deletions app/src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
#include "tx.h"

#include <bech32.h>
#include "chain_config.h"

uint32_t hdPath[HDPATH_LEN_DEFAULT];

uint8_t bech32_hrp_len;
char bech32_hrp[MAX_BECH32_HRP_LEN + 1];
address_encoding_e encoding;

#include "cx.h"

Expand Down Expand Up @@ -94,11 +96,13 @@ zxerr_t crypto_sign(uint8_t *signature,
const uint8_t *message = tx_get_buffer();
const uint16_t messageLen = tx_get_buffer_length();

switch(hdPath[1]) {
case HDPATH_1_DEFAULT:
switch (encoding) {
case BECH32_COSMOS: {
cx_hash_sha256(message, messageLen, messageDigest, CX_SHA256_SIZE);
break;
case HDPATH_ETH_1_DEFAULT: {
}

case BECH32_ETH: {
cx_sha3_t sha3 = {0};
cx_err_t status = cx_keccak_init_no_throw(&sha3, 256);
if (status != CX_OK) {
Expand All @@ -108,8 +112,11 @@ zxerr_t crypto_sign(uint8_t *signature,
if (status != CX_OK) {
return zxerr_ledger_api_error;
}
break;
}
break;

default:
return zxerr_unknown;
}

cx_ecfp_private_key_t cx_privateKey = {0};
Expand Down Expand Up @@ -198,20 +205,32 @@ zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrR
char *addr = (char *) (buffer + PK_LEN_SECP256K1);

uint8_t hashed1_pk[CX_SHA256_SIZE] = {0};
if (isEthPath) {
cx_sha3_t ctx;
if (cx_keccak_init_no_throw(&ctx, 256) != CX_OK) {
return zxerr_unknown;

switch (encoding) {
case BECH32_COSMOS: {
// Hash it
cx_hash_sha256(buffer, PK_LEN_SECP256K1, hashed1_pk, CX_SHA256_SIZE);
uint8_t hashed2_pk[CX_RIPEMD160_SIZE];
ripemd160_32(hashed2_pk, hashed1_pk);
CHECK_ZXERR(bech32EncodeFromBytes(addr, buffer_len - PK_LEN_SECP256K1, bech32_hrp, hashed2_pk, CX_RIPEMD160_SIZE, 1, BECH32_ENCODING_BECH32))
break;
}
cx_hash((cx_hash_t *)&ctx, CX_LAST, uncompressedPubkey+1, sizeof(uncompressedPubkey)-1, hashed1_pk, sizeof(hashed1_pk));
CHECK_ZXERR(bech32EncodeFromBytes(addr, buffer_len - PK_LEN_SECP256K1, bech32_hrp, hashed1_pk + 12, sizeof(hashed1_pk) - 12, 1, BECH32_ENCODING_BECH32))
} else {
// Hash it
cx_hash_sha256(buffer, PK_LEN_SECP256K1, hashed1_pk, CX_SHA256_SIZE);
uint8_t hashed2_pk[CX_RIPEMD160_SIZE];
ripemd160_32(hashed2_pk, hashed1_pk);
CHECK_ZXERR(bech32EncodeFromBytes(addr, buffer_len - PK_LEN_SECP256K1, bech32_hrp, hashed2_pk, CX_RIPEMD160_SIZE, 1, BECH32_ENCODING_BECH32))

case BECH32_ETH: {
cx_sha3_t ctx;
if (cx_keccak_init_no_throw(&ctx, 256) != CX_OK) {
return zxerr_unknown;
}
cx_hash((cx_hash_t *)&ctx, CX_LAST, uncompressedPubkey+1, sizeof(uncompressedPubkey)-1, hashed1_pk, sizeof(hashed1_pk));
CHECK_ZXERR(bech32EncodeFromBytes(addr, buffer_len - PK_LEN_SECP256K1, bech32_hrp, hashed1_pk + 12, sizeof(hashed1_pk) - 12, 1, BECH32_ENCODING_BECH32))
break;
}

default:
*addrResponseLen = 0;
return zxerr_encoding_failed;
}

*addrResponseLen = PK_LEN_SECP256K1 + strnlen(addr, (buffer_len - PK_LEN_SECP256K1));

return zxerr_ok;
Expand Down
4 changes: 3 additions & 1 deletion app/src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ extern "C" {
#define MAX_BECH32_HRP_LEN 83u

extern uint32_t hdPath[HDPATH_LEN_DEFAULT];
extern char *hrp;
extern char bech32_hrp[MAX_BECH32_HRP_LEN + 1];
extern uint8_t bech32_hrp_len;
extern address_encoding_e encoding;

uint8_t extractHRP(uint32_t rx, uint32_t offset);

Expand Down
2 changes: 1 addition & 1 deletion tests_zemu/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"Ledger"
],
"scripts": {
"test": "ts-node tests/pullImageKillOld.ts && jest"
"test": "ts-node tests/pullImageKillOld.ts && jest --maxConcurrency 2"
},
"dependencies": {
"@zondax/ledger-cosmos-js": "^3.0.2",
Expand Down
Binary file modified tests_zemu/snapshots/s-mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/s-mainmenu/00010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/s-show_eth_address/00000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/s-show_eth_address/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/sp-mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/sp-mainmenu/00010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/sp-show_eth_address/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/x-mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/x-mainmenu/00010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/x-show_eth_address/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 3 additions & 7 deletions tests_zemu/tests/json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,7 @@ describe('Json', function () {
const app = new CosmosApp(sim.getTransport())

// Activate expert mode
await sim.clickRight()
await sim.clickBoth()
await sim.clickLeft()
await sim.toggleExpertMode();

const path = [44, 118, 0, 0, 0]
const tx = Buffer.from(JSON.stringify(example_tx_str_msgMultiSend))
Expand Down Expand Up @@ -373,15 +371,13 @@ describe('Json', function () {
const app = new CosmosApp(sim.getTransport())

// Change to expert mode so we can skip fields
await sim.clickRight()
await sim.clickBoth()
await sim.clickLeft()
await sim.toggleExpertMode();

const path = [44, 60, 0, 0, 0]
const tx = Buffer.from(JSON.stringify(setWithdrawAddress))

// get address / publickey
const respPk = await app.getAddressAndPubKey(path, 'cosmos')
const respPk = await app.getAddressAndPubKey(path, 'inj')
expect(respPk.return_code).toEqual(0x9000)
expect(respPk.error_message).toEqual('No errors')
console.log(respPk)
Expand Down
26 changes: 17 additions & 9 deletions tests_zemu/tests/standard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import secp256k1 from 'secp256k1/elliptic'
// @ts-ignore
import crypto from 'crypto'

jest.setTimeout(60000)
jest.setTimeout(90000)

describe('Standard', function () {
// eslint-disable-next-line jest/expect-expect
Expand Down Expand Up @@ -129,7 +129,13 @@ describe('Standard', function () {

// Derivation path. First 3 items are automatically hardened!
const path = [44, 60, 0, 0, 1]
const hrp = 'cosmos'
const hrp = 'inj'

// check with invalid HRP
const errorRespPk = await app.getAddressAndPubKey(path, 'cosmos')
expect(errorRespPk.return_code).toEqual(0x6986)
expect(errorRespPk.error_message).toEqual('Transaction rejected')

const respRequest = app.showAddressAndPubKey(path, hrp)
// Wait until we are not in the main menu
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot())
Expand Down Expand Up @@ -157,8 +163,7 @@ describe('Standard', function () {
const eth_address = bech32.encode(hrp, bech32.toWords(ethereumAddressBuffer)); // "cosmos15n2h0lzvfgc8x4fm6fdya89n78x6ee2fm7fxr3"

expect(resp.bech32_address).toEqual(eth_address)
expect(resp.bech32_address).toEqual('cosmos15n2h0lzvfgc8x4fm6fdya89n78x6ee2fm7fxr3')

expect(resp.bech32_address).toEqual('inj15n2h0lzvfgc8x4fm6fdya89n78x6ee2f3h7z3f')
} finally {
await sim.close()
}
Expand Down Expand Up @@ -189,9 +194,7 @@ describe('Standard', function () {
const app = new CosmosApp(sim.getTransport())

// Activate expert mode
await sim.clickRight()
await sim.clickBoth()
await sim.clickLeft()
await sim.toggleExpertMode();

// Derivation path. First 3 items are automatically hardened!
const path = [44, 118, 2147483647, 0, 4294967295]
Expand Down Expand Up @@ -409,8 +412,13 @@ describe('Standard', function () {
const path = [44, 60, 0, 0, 0]
const tx = Buffer.from(JSON.stringify(example_tx_str_basic), "utf-8")

// check with invalid HRP
const errorRespPk = await app.getAddressAndPubKey(path, 'forbiddenHRP')
expect(errorRespPk.return_code).toEqual(0x6986)
expect(errorRespPk.error_message).toEqual('Transaction rejected')

// get address / publickey
const respPk = await app.getAddressAndPubKey(path, 'cosmos')
const respPk = await app.getAddressAndPubKey(path, 'inj')
expect(respPk.return_code).toEqual(0x9000)
expect(respPk.error_message).toEqual('No errors')
console.log(respPk)
Expand Down Expand Up @@ -454,7 +462,7 @@ describe('Standard', function () {
const tx = Buffer.from(JSON.stringify(example_tx_str_basic), "utf-8")

// get address / publickey
const respPk = await app.getAddressAndPubKey(path, 'cosmos')
const respPk = await app.getAddressAndPubKey(path, 'inj')
expect(respPk.return_code).toEqual(0x9000)
expect(respPk.error_message).toEqual('No errors')
console.log(respPk)
Expand Down
Loading

0 comments on commit 99df548

Please sign in to comment.