Skip to content
Closed
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
4 changes: 4 additions & 0 deletions include/keepkey/firmware/binance.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ typedef struct _BinanceTransferMsg BinanceTransferMsg;
typedef struct _BinanceTransferMsg_BinanceInputOutput BinanceInputOutput;
typedef struct _BinanceTransferMsg_BinanceCoin BinanceCoin;

#define BINANCE_MAX_DENOM_LEN 31

bool binance_isValidDenom(const char* denom);
bool binance_validateTransfer(const BinanceTransferMsg* transfer);
bool binance_signTxInit(const HDNode* _node, const BinanceSignTx* _msg);
bool binance_serializeCoin(const BinanceCoin* coin);
bool binance_serializeInputOutput(const BinanceInputOutput* io);
Expand Down
3 changes: 3 additions & 0 deletions include/keepkey/firmware/eos.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ uint32_t eos_actionsRemaining(void);

bool eos_hasActionUnknownDataRemaining(void);

bool eos_isSupportedAction(const EosActionCommon* common);
bool eos_unknownActionPolicyAllows(bool advanced_mode);

/// \returns true iff successful.
bool eos_compileActionUnknown(const EosActionCommon* common,
const EosActionUnknown* action);
Expand Down
9 changes: 9 additions & 0 deletions include/keepkey/firmware/mayachain.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
typedef struct _MayachainSignTx MayachainSignTx;
typedef struct _MayachainMsgDeposit MayachainMsgDeposit;

// Returns true iff `denom` is a plausible MAYAChain denom: non-empty,
// and contains only lowercase alpha, digits, '.', '/', or '-'.
bool mayachain_isValidDenom(const char* denom);

// Deposit asset grammar: as above but uppercase alpha also allowed.
bool mayachain_isValidAsset(const char* asset);
// Deposit signer must be bech32 with the active network's HRP.
bool mayachain_isValidSigner(const char* signer);

bool mayachain_signTxInit(const HDNode* _node, const MayachainSignTx* _msg);
bool mayachain_signTxUpdateMsgSend(const uint64_t amount,
const char* to_address, const char* denom);
Expand Down
25 changes: 24 additions & 1 deletion include/keepkey/firmware/osmosis.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "trezor/crypto/bip32.h"

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

typedef struct _OsmosisSignTx OsmosisSignTx;
Expand All @@ -16,7 +17,8 @@ void debug_intermediate_hash(void);

bool osmosis_signTxInit(const HDNode* _node, const OsmosisSignTx* _msg);

bool osmosis_signTxUpdateMsgSend(const char* amount, const char* to_address);
bool osmosis_signTxUpdateMsgSend(const char* amount, const char* to_address,
const char* denom);

bool osmosis_signTxUpdateMsgDelegate(const char* amount,
const char* delegator_address,
Expand Down Expand Up @@ -66,6 +68,27 @@ bool osmosis_signTxUpdateMsgSwap(const uint64_t pool_id,
const char* token_in_denom,
const char* token_out_min_amount);

#define OSMOSIS_PRECISION 6
#define OSMOSIS_MAX_AMOUNT_DIGITS 32
#define OSMOSIS_MAX_DENOM_LEN 68

// Longest amount a confirm screen renders: the digits, a point, a space and
// the longest denom a message can carry.
#define OSMOSIS_AMOUNT_STR_LEN 103

/**
* Render an integer base-unit amount for a confirm screen:
* ("1500000", "uosmo") -> "1.500000 OSMO".
*
* Only uosmo is scaled — any other denom is shown exactly as the chain states
* it, because the device does not know its precision. Returns false unless the
* amount is a canonical, schema-bounded unsigned decimal and the denomination
* is a schema-bounded Cosmos asset identifier. Native uosmo additionally must
* fit uint64, which is the range accepted by the native-asset display policy.
*/
bool osmosis_formatAmount(char* out, size_t out_len, const char* value,
const char* denom);

bool osmosis_signTxFinalize(uint8_t* public_key, uint8_t* signature);
bool osmosis_signingIsInited(void);
bool osmosis_signingIsFinished(void);
Expand Down
15 changes: 12 additions & 3 deletions include/keepkey/firmware/signtx_tendermint.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@

typedef struct _TendermintSignTx TendermintSignTx;

typedef enum {
TENDERMINT_SIGNING_NONE = 0,
TENDERMINT_SIGNING_COSMOS,
TENDERMINT_SIGNING_GENERIC,
} TendermintSigningType;

bool tendermint_signTxInit(const HDNode* _node, const void* _msg,
const size_t msgsize, const char* denom);
const size_t msgsize, const char* denom,
TendermintSigningType type);
bool tendermint_signTxUpdateMsgSend(const uint64_t amount,
const char* to_address,
const char* chainstr, const char* denom,
Expand Down Expand Up @@ -41,9 +48,11 @@ bool tendermint_signTxUpdateMsgIBCTransfer(
const char* revision_number, const char* revision_height,
const char* chainstr, const char* denom, const char* msgTypePrefix);
bool tendermint_signTxFinalize(uint8_t* public_key, uint8_t* signature);
bool tendermint_signingIsInited(void);
bool tendermint_signingIsInited(TendermintSigningType type);
bool tendermint_signingConfigMatches(const char* chain_name, const char* denom,
const char* message_type_prefix);
bool tendermint_signingIsFinished(void);
void tendermint_signAbort(void);
const void* tendermint_getSignTx(void);

#endif
#endif
6 changes: 6 additions & 0 deletions include/keepkey/firmware/tendermint.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ bool tendermint_pathMismatched(const CoinType* coin, const uint32_t* address_n,
bool tendermint_getAddress(const HDNode* node, const char* prefix,
char* address);

bool tendermint_isValidDenom(const char* denom);

bool tendermint_isValidAsset(const char* asset);

bool tendermint_isValidSigner(const char* signer, const char* hrp);

void tendermint_sha256UpdateEscaped(SHA256_CTX* ctx, const char* s, size_t len);

bool tendermint_snprintf(SHA256_CTX* ctx, char* temp, size_t len,
Expand Down
20 changes: 19 additions & 1 deletion include/keepkey/firmware/thorchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,18 @@
typedef struct _ThorchainSignTx ThorchainSignTx;
typedef struct _ThorchainMsgDeposit ThorchainMsgDeposit;

// Returns true iff denom contains only chars safe in JSON without escaping.
// Valid: [a-z0-9./\-]. Rejects empty string, quotes, backslashes, whitespace.
bool thorchain_isValidDenom(const char* denom);

// Deposit asset grammar: as above but uppercase alpha also allowed.
bool thorchain_isValidAsset(const char* asset);
// Deposit signer must be bech32 with the active network's HRP.
bool thorchain_isValidSigner(const char* signer);

bool thorchain_signTxInit(const HDNode* _node, const ThorchainSignTx* _msg);
bool thorchain_signTxUpdateMsgSend(const uint64_t amount,
const char* to_address);
const char* to_address, const char* denom);
bool thorchain_signTxUpdateMsgDeposit(const ThorchainMsgDeposit* depmsg);
bool thorchain_signTxFinalize(uint8_t* public_key, uint8_t* signature);
bool thorchain_signingIsInited(void);
Expand All @@ -28,4 +37,13 @@ const ThorchainSignTx* thorchain_getThorchainSignTx(void);
// true if thorchain data parsed and confirmed by user, false otherwise
bool thorchain_parseConfirmMemo(const char* swapStr, size_t size);

// Pages the COMPLETE raw memo (ASCII as text pages, binary as hex pages) so no
// byte is ever truncated behind confirm()'s body budget. Native THOR/MAYA
// deposit/send handlers call this as the authoritative disclosure after their
// best-effort structured summary, so a field the structured view omits (or a
// long field that would truncate) can never be signed unseen. Returns false if
// the user rejects any page. Shared by the MAYA path (same memo grammar).
bool thorchain_confirm_full_memo(const char* title, const char* memo,
size_t len);

#endif
76 changes: 66 additions & 10 deletions lib/firmware/binance.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,49 @@ static BinanceSignTx msg;

const BinanceSignTx* binance_getBinanceSignTx(void) { return &msg; }

bool binance_isValidDenom(const char* denom) {
if (!denom) return false;
const size_t len = strnlen(denom, BINANCE_MAX_DENOM_LEN + 1);
if (len == 0 || len > BINANCE_MAX_DENOM_LEN) return false;
for (size_t i = 0; i < len; i++) {
const char c = denom[i];
if (!((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-'))
return false;
}
return true;
}

bool binance_validateTransfer(const BinanceTransferMsg* transfer) {
if (!transfer || transfer->inputs_count != 1 ||
transfer->inputs[0].coins_count != 1 || transfer->outputs_count != 1 ||
transfer->outputs[0].coins_count != 1)
return false;

const BinanceInputOutput* input = &transfer->inputs[0];
const BinanceInputOutput* output = &transfer->outputs[0];
const BinanceCoin* input_coin = &input->coins[0];
const BinanceCoin* output_coin = &output->coins[0];
if (!input->has_address || !output->has_address || !input_coin->has_amount ||
!output_coin->has_amount || !input_coin->has_denom ||
!output_coin->has_denom || input_coin->amount <= 0 ||
output_coin->amount <= 0 || input_coin->amount != output_coin->amount ||
strcmp(input_coin->denom, output_coin->denom) != 0 ||
!binance_isValidDenom(input_coin->denom))
return false;

return true;
}

bool binance_signTxInit(const HDNode* _node, const BinanceSignTx* _msg) {
initialized = true;
binance_signAbort();
if (!_node || !_msg || !_msg->has_msg_count || _msg->msg_count == 0 ||
!_msg->has_account_number || _msg->account_number < 0 ||
!_msg->has_chain_id || _msg->chain_id[0] == '\0' || !_msg->has_sequence ||
_msg->sequence < 0 || !_msg->has_source || _msg->source < 0)
return false;

msgs_remaining = _msg->msg_count;
has_message = false;

memzero(&node, sizeof(node));
memcpy(&node, _node, sizeof(node));
memcpy(&msg, _msg, sizeof(msg));

Expand All @@ -32,7 +69,7 @@ bool binance_signTxInit(const HDNode* _node, const BinanceSignTx* _msg) {

success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer),
"{\"account_number\":\"%" PRIu64 "\"",
msg.account_number);
(uint64_t)msg.account_number);

const char* const chainid_prefix = ",\"chain_id\":\"";
sha256_Update(&ctx, (uint8_t*)chainid_prefix, strlen(chainid_prefix));
Expand All @@ -45,16 +82,25 @@ bool binance_signTxInit(const HDNode* _node, const BinanceSignTx* _msg) {
}

sha256_Update(&ctx, (const uint8_t*)"\",\"msgs\":[", 10);
return success;
if (!success) {
binance_signAbort();
return false;
}
initialized = true;
return true;
}

bool binance_serializeCoin(const BinanceCoin* coin) {
if (!coin || !coin->has_amount || coin->amount <= 0 || !coin->has_denom ||
!binance_isValidDenom(coin->denom))
return false;

bool success = true;
char buffer[64 + 1];

success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer),
"{\"amount\":%" PRIu64 ",\"denom\":\"%s\"}",
coin->amount, coin->denom);
(uint64_t)coin->amount, coin->denom);

return success;
}
Expand Down Expand Up @@ -83,6 +129,9 @@ bool binance_serializeInputOutput(const BinanceInputOutput* io) {
}

bool binance_signTxUpdateTransfer(const BinanceTransferMsg* _msg) {
if (!initialized || msgs_remaining == 0 || !binance_validateTransfer(_msg))
return false;

bool success = true;

sha256_Update(&ctx, (const uint8_t*)"{\"inputs\":[", 11);
Expand All @@ -103,18 +152,23 @@ bool binance_signTxUpdateTransfer(const BinanceTransferMsg* _msg) {

sha256_Update(&ctx, (const uint8_t*)"]}", 2);

has_message = true;
msgs_remaining--;
if (success) {
has_message = true;
msgs_remaining--;
}
return success;
}

bool binance_signTxFinalize(uint8_t* public_key, uint8_t* signature) {
if (!initialized || msgs_remaining != 0 || !has_message || !public_key ||
!signature)
return false;
char buffer[64 + 1];

if (!tendermint_snprintf(&ctx, buffer, sizeof(buffer),
"],\"sequence\":\"%" PRIu64
"\",\"source\":\"%" PRIu64 "\"}",
msg.sequence, msg.source))
(uint64_t)msg.sequence, (uint64_t)msg.source))
return false;

hdnode_fill_public_key(&node);
Expand All @@ -128,7 +182,9 @@ bool binance_signTxFinalize(uint8_t* public_key, uint8_t* signature) {

bool binance_signingIsInited(void) { return initialized; }

bool binance_signingIsFinished(void) { return msgs_remaining == 0; }
bool binance_signingIsFinished(void) {
return initialized && msgs_remaining == 0 && has_message;
}

void binance_signAbort(void) {
initialized = false;
Expand Down
26 changes: 20 additions & 6 deletions lib/firmware/eos.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ bool eos_compilePermissionLevel(const EosPermissionLevel* auth) {

bool eos_hasActionUnknownDataRemaining(void) { return 0 < unknown_remaining; }

static bool isSupportedAction(const EosActionCommon* common) {
bool eos_isSupportedAction(const EosActionCommon* common) {
if (common->account == EOS_eosio || common->account == EOS_eosio_token) {
switch (common->name) {
case EOS_Transfer:
Expand All @@ -402,26 +402,34 @@ static bool isSupportedAction(const EosActionCommon* common) {
case EOS_DeleteAuth:
case EOS_LinkAuth:
case EOS_UnlinkAuth:
case EOS_NewAccount:
return true;
}
}
return false;
}

bool eos_unknownActionPolicyAllows(bool advanced_mode) { return advanced_mode; }

bool eos_compileActionUnknown(const EosActionCommon* common,
const EosActionUnknown* action) {
if (isSupportedAction(common)) {
if (eos_isSupportedAction(common)) {
fsm_sendFailure(
FailureType_Failure_SyntaxError,
"EosActionUnknown cannot be used with supported contract actions");
eos_signingAbort();
return false;
}

if (!storage_isPolicyEnabled("AdvancedMode")) {
(void)review(ButtonRequestType_ButtonRequest_Other, "Warning",
"Signing of arbitrary EOS actions is recommended only for "
"experienced users. Enable 'AdvancedMode' policy to dismiss.");
if (!eos_unknownActionPolicyAllows(storage_isPolicyEnabled("AdvancedMode"))) {
(void)review(ButtonRequestType_ButtonRequest_Other, "Blocked",
"Arbitrary EOS actions require AdvancedMode. "
"Enable in device settings.");
fsm_sendFailure(FailureType_Failure_ActionCancelled,
"Arbitrary EOS action signing disabled by policy");
eos_signingAbort();
layoutHome();
return false;
}

if (unknown_remaining == 0) {
Expand Down Expand Up @@ -534,7 +542,13 @@ bool eos_signTx(EosSignedTx* tx) {

time_t expiry = header.expiration;
char expiry_str[26];
#ifdef _WIN32
// asctime_s is the bounds-checked Windows variant; output truncated below.
// cppcheck-suppress asctime_sCalled
asctime_s(expiry_str, sizeof(expiry_str), gmtime(&expiry));
#else
asctime_r(gmtime(&expiry), expiry_str);
#endif
expiry_str[24] = 0; // cut off the '\n'
uint32_t delay = header.delay_sec;
if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Sign Transaction",
Expand Down
Loading
Loading