Skip to content

Commit

Permalink
Sign personal (#27)
Browse files Browse the repository at this point in the history
* add sign_personal

* update js package

* update snapshots
  • Loading branch information
chcmedeiros authored Nov 29, 2024
1 parent 2a73783 commit c347914
Show file tree
Hide file tree
Showing 96 changed files with 360 additions and 17 deletions.
8 changes: 8 additions & 0 deletions app/src/apdu_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,14 @@ void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
handleSignEth(flags, tx, rx);
break;
}
case INS_SIGN_PERSONAL_MESSAGE: {
CHECK_PIN_VALIDATED()
if (cla != CLA_ETH) {
THROW(APDU_CODE_COMMAND_NOT_ALLOWED);
}
handleSignEip191(flags, tx, rx);
break;
}
default:
THROW(APDU_CODE_INS_NOT_SUPPORTED);
}
Expand Down
22 changes: 21 additions & 1 deletion app/src/common/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "coin.h"
#include "crypto.h"
#include "crypto_eth.h"
#include "eth_eip191.h"
#include "tx.h"
#include "zxerror.h"

Expand Down Expand Up @@ -93,7 +94,7 @@ __Z_INLINE void app_sign_eth() {
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(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength, &replyLen, false);

if (err != zxerr_ok || replyLen == 0) {
set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR);
Expand All @@ -104,6 +105,25 @@ __Z_INLINE void app_sign_eth() {
}
}

__Z_INLINE void app_sign_eip191() {
const uint8_t *message = tx_get_buffer();
const uint16_t messageLength = tx_get_buffer_length();
uint16_t replyLen = 0;
uint8_t hash[32] = {0};
MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE);
zxerr_t err = eip191_hash_message(message, messageLength, hash);
if (err == zxerr_ok) {
err = crypto_sign_eth(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, hash, 32, &replyLen, true);
}
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
80 changes: 80 additions & 0 deletions app/src/evm/apdu_handler_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "coin_eth.h"
#include "crypto_eth.h"
#include "eth_addr.h"
#include "eth_eip191.h"
#include "eth_utils.h"
#include "tx_eth.h"
#include "view.h"
Expand Down Expand Up @@ -59,6 +60,67 @@ void extract_eth_path(uint32_t rx, uint32_t offset) {
hdPathEth_len = path_len;
}

uint32_t bytes_to_read;
bool process_chunk_eip191(__Z_UNUSED volatile uint32_t *tx, uint32_t rx) {
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);
}
uint8_t *data = &(G_io_apdu_buffer[OFFSET_DATA]);
uint32_t len = rx - OFFSET_DATA;
uint64_t added;
switch (payloadType) {
case P1_ETH_FIRST:
tx_initialize();
tx_reset();
extract_eth_path(rx, OFFSET_DATA);
// there is not warranties that the first chunk
// contains the serialized path only;
// so we need to offset the data to point to the first transaction
// byte
uint32_t path_len = sizeof(uint32_t) * hdPathEth_len;
// plus the first offset data containing the path len
data += path_len + 1;
if (len < path_len) {
THROW(APDU_CODE_WRONG_LENGTH);
}
len -= path_len + 1;
// now process the chunk
bytes_to_read = U4BE(data, 0);
bytes_to_read -= len - sizeof(uint32_t);
added = tx_append(data, len);
if (added != len) {
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}
tx_initialized = true;
if (bytes_to_read == 0) {
tx_initialized = false;
return true;
}
return false;
case P1_ETH_MORE:
if (!tx_initialized) {
THROW(APDU_CODE_TX_NOT_INITIALIZED);
}
// either the entire buffer of the remaining bytes we expect
bytes_to_read -= len;
added = tx_append(data, len);
if (added != len) {
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}
// check if this chunk was the last one
if (bytes_to_read == 0) {
tx_initialized = false;
return true;
}
return false;
}
THROW(APDU_CODE_INVALIDP1P2);
}

bool process_chunk_eth(__Z_UNUSED volatile uint32_t *tx, uint32_t rx) {
const uint8_t payloadType = G_io_apdu_buffer[OFFSET_PAYLOAD_TYPE];

Expand Down Expand Up @@ -209,3 +271,21 @@ void handleSignEth(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx)
view_review_show(REVIEW_TXN);
*flags |= IO_ASYNCH_REPLY;
}

void handleSignEip191(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
zemu_log_stack("handleSignEip191");
if (!process_chunk_eip191(tx, rx)) {
THROW(APDU_CODE_OK);
}
CHECK_APP_CANARY()
parser_error_t err = eip191_msg_parse();
if (err == parser_blindsign_required) {
*flags |= IO_ASYNCH_REPLY;
view_blindsign_error_show();
THROW(APDU_CODE_DATA_INVALID);
}
CHECK_APP_CANARY()
view_review_init(eip191_msg_getItem, eip191_msg_getNumItems, app_sign_eip191);
view_review_show(REVIEW_TXN);
*flags |= IO_ASYNCH_REPLY;
}
2 changes: 1 addition & 1 deletion app/src/evm/apdu_handler_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ extern "C" {

void handleGetAddrEth(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx);
void handleSignEth(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx);

void handleSignEip191(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx);
#ifdef __cplusplus
}
#endif
1 change: 1 addition & 0 deletions app/src/evm/coin_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern "C" {

#define INS_SIGN_ETH 0x04
#define INS_GET_ADDR_ETH 0x02
#define INS_SIGN_PERSONAL_MESSAGE 0x08

#define VIEW_ADDRESS_OFFSET_ETH (SECP256K1_PK_LEN + 1 + 1)

Expand Down
10 changes: 7 additions & 3 deletions app/src/evm/crypto_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,17 @@ zxerr_t _sign(uint8_t *output, uint16_t outputLen, const uint8_t *message, uint1

// Sign an ethereum related transaction
zxerr_t crypto_sign_eth(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen,
uint16_t *sigSize) {
uint16_t *sigSize, bool personal_msg) {
if (buffer == NULL || message == NULL || sigSize == NULL || signatureMaxlen < sizeof(signature_t)) {
return zxerr_invalid_crypto_settings;
}

uint8_t message_digest[KECCAK_256_SIZE] = {0};
CHECK_ZXERR(keccak_digest(message, messageLen, message_digest, KECCAK_256_SIZE))
if (!personal_msg) {
CHECK_ZXERR(keccak_digest(message, messageLen, message_digest, KECCAK_256_SIZE))
} else {
MEMCPY(message_digest, message, messageLen);
}

unsigned int info = 0;
zxerr_t error = _sign(buffer, signatureMaxlen, message_digest, KECCAK_256_SIZE, sigSize, &info);
Expand All @@ -155,7 +159,7 @@ zxerr_t crypto_sign_eth(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t

// we need to fix V
uint8_t v = 0;
error = tx_compute_eth_v(info, &v);
error = tx_compute_eth_v(info, &v, personal_msg);

if (error != zxerr_ok) return zxerr_invalid_crypto_settings;

Expand Down
2 changes: 1 addition & 1 deletion app/src/evm/crypto_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ extern uint32_t hdPathEth_len;
extern uint8_t flr_chain_code;
zxerr_t crypto_fillEthAddress(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrLen);
zxerr_t crypto_sign_eth(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen,
uint16_t *sigSize);
uint16_t *sigSize, bool personal_msg);
zxerr_t keccak_digest(const unsigned char *in, unsigned int inLen, unsigned char *out, unsigned int outLen);

#ifdef __cplusplus
Expand Down
114 changes: 114 additions & 0 deletions app/src/evm/eth_eip191.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*******************************************************************************
* (c) 2018 - 2024 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 "eth_eip191.h"

#include "actions.h"
#include "apdu_handler_eth.h"
#include "app_main.h"
#include "app_mode.h"
#include "coin_eth.h"
#include "parser_common.h"
#include "zxformat.h"
#include "zxmacros.h"
#if defined(LEDGER_SPECIFIC)
#include "cx.h"
#else
#define CX_SHA256_SIZE 32
#define CX_RIPEMD160_SIZE 20
#endif
static const char SIGN_MAGIC[] =
"\x19"
"Ethereum Signed Message:\n";
zxerr_t eip191_msg_getNumItems(uint8_t *num_items) {
zemu_log_stack("msg_getNumItems");
*num_items = 2;
return zxerr_ok;
}
zxerr_t eip191_msg_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount) {
ZEMU_LOGF(200, "[msg_getItem] %d/%d\n", displayIdx, pageIdx)
MEMZERO(outKey, outKeyLen);
MEMZERO(outVal, outValLen);
snprintf(outKey, outKeyLen, "?");
snprintf(outVal, outValLen, " ");
*pageCount = 1;
const uint8_t *message = tx_get_buffer() + sizeof(uint32_t);
const uint16_t messageLength = tx_get_buffer_length() - sizeof(uint32_t);
switch (displayIdx) {
case 0: {
snprintf(outKey, outKeyLen, "Sign");
snprintf(outVal, outValLen, "Personal Message");
return zxerr_ok;
}
case 1: {
snprintf(outKey, outKeyLen, "Msg hex");
uint16_t npc = 0; // Non Printable Chars Counter
for (uint16_t i = 0; i < messageLength; i++) {
npc += IS_PRINTABLE(message[i]) ? 0 /* Printable Char */ : 1 /* Non Printable Char */;
}
// msg in hex in case >= than 40% is non printable
// or first char is not printable.
if (messageLength > 0 && (npc * 100) / messageLength >= 40) {
pageStringHex(outVal, outValLen, (const char *)message, messageLength, pageIdx, pageCount);
return zxerr_ok;
}
// print message
snprintf(outKey, outKeyLen, "Msg");
pageString(outVal, outValLen, (const char *)message, pageIdx, pageCount);
return zxerr_ok;
}
default:
return zxerr_no_data;
}
return zxerr_ok;
}
parser_error_t eip191_msg_parse() {
const uint8_t *message = tx_get_buffer() + sizeof(uint32_t);
const uint16_t messageLength = tx_get_buffer_length() - sizeof(uint32_t);
uint16_t npc = 0; // Non Printable Chars Counter
for (uint16_t i = 0; i < messageLength; i++) {
npc += IS_PRINTABLE(message[i]) ? 0 /* Printable Char */ : 1 /* Non Printable Char */;
}
// msg in hex in case >= than 40% is non printable
// or first char is not printable.
if (messageLength > 0 && (npc * 100) / messageLength >= 40 && !app_mode_blindsign()) {
return parser_blindsign_required;
} else if (messageLength > 0 && (npc * 100) / messageLength < 40) {
app_mode_skip_blindsign_ui();
}

return parser_ok;
}
zxerr_t eip191_hash_message(const uint8_t *message, uint16_t messageLen, uint8_t *hash) {
zemu_log_stack("eip191_hash_message");
if (message == NULL || messageLen == 0) {
return zxerr_unknown;
}
MEMZERO(hash, 32);
#if defined(LEDGER_SPECIFIC)
cx_sha3_t sha3;
CHECK_CX_OK(cx_keccak_init_no_throw(&sha3, 256));
CHECK_CX_OK(cx_hash_no_throw((cx_hash_t *)&sha3, 0, (uint8_t *)SIGN_MAGIC, sizeof(SIGN_MAGIC) - 1, NULL, 0));
uint32_t msg_len = U4BE(message, 0);
char len_str[12] = {0};
uint32_to_str(len_str, sizeof(len_str), msg_len);
CHECK_CX_OK(cx_hash_no_throw((cx_hash_t *)&sha3, 0, (uint8_t *)len_str, strlen(len_str), NULL, 0));
CHECK_CX_OK(
cx_hash_no_throw((cx_hash_t *)&sha3, CX_LAST, message + sizeof(uint32_t), messageLen - sizeof(uint32_t), hash, 32));
#endif
zemu_log_stack("eip191_hash_message done");
return zxerr_ok;
}
34 changes: 34 additions & 0 deletions app/src/evm/eth_eip191.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* (c) 2018 - 2024 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
#include <stdbool.h>
#include <stdint.h>

#include "coin_eth.h"
#include "parser_common.h"
#include "zxerror.h"
#include "zxmacros.h"
#ifdef __cplusplus
extern "C" {
#endif
parser_error_t eip191_msg_parse();
zxerr_t eip191_msg_getNumItems(uint8_t *num_items);
zxerr_t eip191_msg_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount);
zxerr_t eip191_hash_message(const uint8_t *message, uint16_t messageLen, uint8_t *hash);
#ifdef __cplusplus
}
#endif
4 changes: 2 additions & 2 deletions app/src/evm/parser_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,6 @@ parser_error_t parser_getItemEth(const parser_context_t *ctx, uint8_t displayIdx
return _getItemEth(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, pageCount);
}

parser_error_t parser_compute_eth_v(parser_context_t *ctx, unsigned int info, uint8_t *v) {
return _computeV(ctx, &eth_tx_obj, info, v);
parser_error_t parser_compute_eth_v(parser_context_t *ctx, unsigned int info, uint8_t *v, bool personal_msg) {
return _computeV(ctx, &eth_tx_obj, info, v, personal_msg);
}
3 changes: 2 additions & 1 deletion app/src/evm/parser_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>

#include "parser_impl.h"

Expand All @@ -38,7 +39,7 @@ parser_error_t parser_getNumItemsEth(const parser_context_t *ctx, uint8_t *num_i
parser_error_t parser_getItemEth(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_error_t parser_compute_eth_v(parser_context_t *ctx, unsigned int info, uint8_t *v);
parser_error_t parser_compute_eth_v(parser_context_t *ctx, unsigned int info, uint8_t *v, bool personal_msg);
#ifdef __cplusplus
}
#endif
Loading

0 comments on commit c347914

Please sign in to comment.