Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deps/device-protocol
4 changes: 4 additions & 0 deletions include/keepkey/board/confirm_sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ bool confirm(ButtonRequestType type, const char *request_title,
const char *request_body, ...)
__attribute__((format(printf, 3, 4)));

bool confirm_with_icon(ButtonRequestType type, IconType iconNum,
const char *request_title, const char *request_body,
...) __attribute__((format(printf, 4, 5)));

bool confirm_constant_power(ButtonRequestType type, const char *request_title, const char *request_body,
...) __attribute__((format(printf, 3, 4)));

Expand Down
1 change: 1 addition & 0 deletions include/keepkey/board/layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ typedef enum {
typedef enum {
NO_ICON=0,
ETHEREUM_ICON,
VERIFIED_ICON,
} IconType;

typedef void (*AnimateCallback)(void *data, uint32_t duration,
Expand Down
1 change: 1 addition & 0 deletions include/keepkey/firmware/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ static const PolicyType policies[] = {
{true, "Experimental", true, false},
{true, "AdvancedMode", true, false},
{true, "SolBlindSign", true, false},
{true, "EthBlindSign", true, true},
};

int run_policy_compile_output(const CoinType *coin, const HDNode *root,
Expand Down
62 changes: 62 additions & 0 deletions include/keepkey/firmware/signed_metadata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#ifndef KEEPKEY_FIRMWARE_SIGNED_METADATA_H
#define KEEPKEY_FIRMWARE_SIGNED_METADATA_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

typedef struct _EthereumSignTx EthereumSignTx;

#define METADATA_MAX_ARGS 8
#define METADATA_MAX_METHOD_LEN 64
#define METADATA_MAX_ARG_NAME_LEN 32
#define METADATA_MAX_ARG_VALUE_LEN 32
#define METADATA_MAX_KEYS 4

typedef enum {
METADATA_OPAQUE = 0,
METADATA_VERIFIED = 1,
METADATA_MALFORMED = 2,
} MetadataClassification;

typedef enum {
ARG_FORMAT_RAW = 0,
ARG_FORMAT_ADDRESS = 1,
ARG_FORMAT_AMOUNT = 2,
ARG_FORMAT_BYTES = 3,
} ArgFormat;

typedef struct {
char name[METADATA_MAX_ARG_NAME_LEN + 1];
ArgFormat format;
uint8_t value[METADATA_MAX_ARG_VALUE_LEN];
uint16_t value_len;
} MetadataArg;

typedef struct {
uint8_t version;
uint32_t chain_id;
uint8_t contract_address[20];
uint8_t selector[4];
uint8_t tx_hash[32];
char method_name[METADATA_MAX_METHOD_LEN + 1];
uint8_t num_args;
MetadataArg args[METADATA_MAX_ARGS];
MetadataClassification classification;
uint32_t timestamp;
uint8_t key_id;
uint8_t signature[64];
uint8_t recovery;
} SignedMetadata;

bool signed_metadata_available(void);
void signed_metadata_clear(void);
MetadataClassification signed_metadata_process(const uint8_t *payload,
size_t payload_len,
uint8_t key_id);
bool signed_metadata_matches_tx(const EthereumSignTx *msg,
const uint8_t *tx_hash);
bool signed_metadata_confirm(void);
const SignedMetadata *signed_metadata_get(void);

#endif
3 changes: 3 additions & 0 deletions include/keepkey/transport/messages-ethereum.options
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ Ethereum712TypesValues.eip712types max_size:2048
Ethereum712TypesValues.eip712primetype max_size:80
Ethereum712TypesValues.eip712data max_size:2048

EthereumTxMetadata.signed_payload max_size:1024
EthereumMetadataAck.display_summary max_size:32

2 changes: 1 addition & 1 deletion include/keepkey/transport/messages.options
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Features.label max_size:33
Features.coins max_count:0
Features.revision max_size:41
Features.bootloader_hash max_size:32
Features.policies max_count:5
Features.policies max_count:6
Features.model max_size:32
Features.firmware_variant max_size:32
Features.firmware_hash max_size:32
Expand Down
22 changes: 22 additions & 0 deletions lib/board/confirm_sm.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,28 @@ bool confirm(ButtonRequestType type, const char *request_title, const char *requ
return ret;
}

bool confirm_with_icon(ButtonRequestType type, IconType iconNum,
const char *request_title, const char *request_body,
...)
{
button_request_acked = false;

va_list vl;
va_start(vl, request_body);
vsnprintf(strbuf, sizeof(strbuf), request_body, vl);
va_end(vl);

ButtonRequest resp;
memset(&resp, 0, sizeof(ButtonRequest));
resp.has_code = true;
resp.code = type;
msg_write(MessageType_MessageType_ButtonRequest, &resp);

bool ret = confirm_helper(request_title, strbuf, &layout_standard_notification, false, iconNum, false);
memzero(strbuf, sizeof(strbuf));
return ret;
}

bool confirm_constant_power(ButtonRequestType type, const char *request_title, const char *request_body,
...)
{
Expand Down
6 changes: 6 additions & 0 deletions lib/board/layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,12 @@ void layout_add_icon(IconType type) {
draw_bitmap_mono_rle(canvas, get_ethereum_icon_frame(), false);
break;

case VERIFIED_ICON:
/* TODO: replace with dedicated verified/shield bitmap.
* Using Ethereum icon as placeholder until bitmap is designed. */
draw_bitmap_mono_rle(canvas, get_ethereum_icon_frame(), false);
break;

default:
/* no action requires */
break;
Expand Down
1 change: 1 addition & 0 deletions lib/firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ if(NOT "${COIN_SUPPORT}" STREQUAL "BTC")
eos-contracts/eosio.token.c
ethereum.c
ethereum_contracts.c
signed_metadata.c
ethereum_contracts/makerdao.c
ethereum_contracts/saproxy.c
ethereum_contracts/zxappliquid.c
Expand Down
36 changes: 33 additions & 3 deletions lib/firmware/ethereum.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "keepkey/firmware/eip712.h"
#include "keepkey/firmware/ethereum_contracts.h"
#include "keepkey/firmware/ethereum_contracts/makerdao.h"
#include "keepkey/firmware/signed_metadata.h"
#include "keepkey/firmware/ethereum_tokens.h"
#include "keepkey/firmware/storage.h"
#include "keepkey/firmware/thorchain.h"
Expand Down Expand Up @@ -689,6 +690,26 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node,
data_needs_confirm = false;
}

// Signed metadata clear signing (backwards compatible).
// Only fires if host sent EthereumTxMetadata before this EthereumSignTx.
if (data_needs_confirm && data_total > 0 && signed_metadata_available()) {
if (signed_metadata_matches_tx(msg, NULL)) {
if (signed_metadata_confirm()) {
needs_confirm = false;
data_needs_confirm = false;
} else {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
"Signing cancelled by user");
ethereum_signing_abort();
signed_metadata_clear();
return;
}
}
}
// Always clear metadata after use — prevents stale data from persisting
// when contractHandled or ERC-20 paths bypass the metadata check above.
signed_metadata_clear();

// detect ERC-20 token
if (data_total == 68 && ethereum_isStandardERC20Transfer(msg)) {
token = tokenByChainAddress(chain_id, msg->to.bytes);
Expand Down Expand Up @@ -734,10 +755,19 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node,

memset(confirm_body_message, 0, sizeof(confirm_body_message));
if (token == NULL && data_total > 0 && data_needs_confirm) {
// EthBlindSign policy: hard gate when disabled
if (!storage_isPolicyEnabled("EthBlindSign")) {
(void)review(ButtonRequestType_ButtonRequest_Other, "Blocked",
"Blind signing is disabled. Enable "
"'EthBlindSign' policy to allow.");
fsm_sendFailure(FailureType_Failure_ActionCancelled,
"Blind signing disabled by policy");
ethereum_signing_abort();
return;
}

// KeepKey custom: warn the user that they're trying to do something
// that is potentially dangerous. People (generally) aren't great at
// parsing raw transaction data, and we can't effectively show them
// what they're about to do in the general case.
// that is potentially dangerous.
if (!storage_isPolicyEnabled("AdvancedMode")) {
(void)review(
ButtonRequestType_ButtonRequest_Other, "Warning",
Expand Down
5 changes: 5 additions & 0 deletions lib/firmware/fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@
#include "messages-zcash.pb.h"
#endif // BITCOIN_ONLY

// Forward declaration for handler defined in fsm_msg_ethereum.h
#ifndef BITCOIN_ONLY
void fsm_msgEthereumTxMetadata(const EthereumTxMetadata *);
#endif

#define _(X) (X)

static uint8_t msg_resp[MAX_FRAME_SIZE] __attribute__((aligned(4)));
Expand Down
36 changes: 36 additions & 0 deletions lib/firmware/fsm_msg_ethereum.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,42 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

#include "keepkey/firmware/signed_metadata.h"

void fsm_msgEthereumTxMetadata(const EthereumTxMetadata *msg) {
CHECK_INITIALIZED
CHECK_PIN

RESP_INIT(EthereumMetadataAck);

MetadataClassification result = signed_metadata_process(
msg->signed_payload.bytes,
msg->signed_payload.size,
msg->has_key_id ? msg->key_id : 0
);

resp->classification = (uint32_t)result;
resp->has_display_summary = true;

switch (result) {
case METADATA_VERIFIED:
strlcpy(resp->display_summary, "Verified",
sizeof(resp->display_summary));
break;
case METADATA_OPAQUE:
strlcpy(resp->display_summary, "Unverified",
sizeof(resp->display_summary));
break;
case METADATA_MALFORMED:
default:
strlcpy(resp->display_summary, "Invalid",
sizeof(resp->display_summary));
break;
}

msg_write(MessageType_MessageType_EthereumMetadataAck, resp);
}

static int process_ethereum_xfer(const CoinType *coin, EthereumSignTx *msg) {
if (!ethereum_isStandardERC20Transfer(msg) && msg->data_length != 0)
return TXOUT_COMPILE_ERROR;
Expand Down
2 changes: 2 additions & 0 deletions lib/firmware/messagemap.def
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
MSG_IN(MessageType_MessageType_EthereumGetAddress, EthereumGetAddress, fsm_msgEthereumGetAddress)
MSG_IN(MessageType_MessageType_EthereumSignTx, EthereumSignTx, fsm_msgEthereumSignTx)
MSG_IN(MessageType_MessageType_EthereumTxAck, EthereumTxAck, fsm_msgEthereumTxAck)
MSG_IN(MessageType_MessageType_EthereumTxMetadata, EthereumTxMetadata, fsm_msgEthereumTxMetadata)
MSG_IN(MessageType_MessageType_EthereumSignMessage, EthereumSignMessage, fsm_msgEthereumSignMessage)
MSG_IN(MessageType_MessageType_EthereumVerifyMessage, EthereumVerifyMessage, fsm_msgEthereumVerifyMessage)

Expand Down Expand Up @@ -118,6 +119,7 @@
MSG_OUT(MessageType_MessageType_EthereumMessageSignature, EthereumMessageSignature, NO_PROCESS_FUNC)

MSG_OUT(MessageType_MessageType_EthereumTypedDataSignature, EthereumTypedDataSignature, NO_PROCESS_FUNC)
MSG_OUT(MessageType_MessageType_EthereumMetadataAck, EthereumMetadataAck, NO_PROCESS_FUNC)

MSG_OUT(MessageType_MessageType_NanoAddress, NanoAddress, NO_PROCESS_FUNC)
MSG_OUT(MessageType_MessageType_NanoSignedTx, NanoSignedTx, NO_PROCESS_FUNC)
Expand Down
Loading
Loading