Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AOPP support #1903

Merged
merged 11 commits into from
Nov 10, 2021
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
1 change: 1 addition & 0 deletions common/protob/messages-bitcoin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ message SignMessage {
required bytes message = 2; // message to be signed
optional string coin_name = 3 [default='Bitcoin']; // coin to use for signing
optional InputScriptType script_type = 4 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.)
optional bool no_script_type = 5; // don't include script type information in the recovery byte of the signature, same as in Bitcoin Core
}

/**
Expand Down
1 change: 1 addition & 0 deletions core/.changelog.d/1586.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support no_script_type option in SignMessage.
1 change: 1 addition & 0 deletions core/.changelog.d/1586.added.1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Show address confirmation in SignMessage.
23 changes: 17 additions & 6 deletions core/src/apps/bitcoin/sign_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from apps.common.paths import validate_path
from apps.common.signverify import decode_message, message_digest

from .addresses import get_address
from .addresses import address_short, get_address
from .keychain import with_keychain

if False:
Expand All @@ -26,22 +26,33 @@ async def sign_message(
script_type = msg.script_type or InputScriptType.SPENDADDRESS

await validate_path(ctx, keychain, address_n)
await confirm_signverify(ctx, coin.coin_shortcut, decode_message(message))

node = keychain.derive(address_n)
address = get_address(script_type, coin, node)
await confirm_signverify(
ctx,
coin.coin_shortcut,
decode_message(message),
address_short(coin, address),
verify=False,
)

seckey = node.private_key()

address = get_address(script_type, coin, node)
digest = message_digest(coin, message)
signature = secp256k1.sign(seckey, digest)

if script_type == InputScriptType.SPENDADDRESS:
pass
script_type_info = 0
elif script_type == InputScriptType.SPENDP2SHWITNESS:
signature = bytes([signature[0] + 4]) + signature[1:]
script_type_info = 4
elif script_type == InputScriptType.SPENDWITNESS:
signature = bytes([signature[0] + 8]) + signature[1:]
script_type_info = 8
else:
raise wire.ProcessError("Unsupported script type")

# Add script type information to the recovery byte.
if script_type_info != 0 and not msg.no_script_type:
signature = bytes([signature[0] + script_type_info]) + signature[1:]

return MessageSignature(address=address, signature=signature)
1 change: 1 addition & 0 deletions core/src/apps/bitcoin/verify_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ async def verify_message(ctx: wire.Context, msg: VerifyMessage) -> Success:
coin.coin_shortcut,
decode_message(message),
address=address_short(coin, address),
verify=True,
)

return Success(message="Message verified")
8 changes: 6 additions & 2 deletions core/src/apps/ethereum/sign_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,13 @@ async def sign_message(
ctx: Context, msg: EthereumSignMessage, keychain: Keychain
) -> EthereumMessageSignature:
await paths.validate_path(ctx, keychain, msg.address_n)
await confirm_signverify(ctx, "ETH", decode_message(msg.message))

node = keychain.derive(msg.address_n)
address = address_from_bytes(node.ethereum_pubkeyhash())
await confirm_signverify(
ctx, "ETH", decode_message(msg.message), address, verify=False
)

signature = secp256k1.sign(
node.private_key(),
message_digest(msg.message),
Expand All @@ -42,6 +46,6 @@ async def sign_message(
)

return EthereumMessageSignature(
address=address_from_bytes(node.ethereum_pubkeyhash()),
address=address,
signature=signature[1:] + bytearray([signature[0]]),
)
4 changes: 3 additions & 1 deletion core/src/apps/ethereum/verify_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ async def verify_message(ctx: Context, msg: EthereumVerifyMessage) -> Success:

address = address_from_bytes(address_bytes)

await confirm_signverify(ctx, "ETH", decode_message(msg.message), address=address)
await confirm_signverify(
ctx, "ETH", decode_message(msg.message), address=address, verify=True
)

return Success(message="Message verified")
2 changes: 2 additions & 0 deletions core/src/trezor/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ class SignMessage(protobuf.MessageType):
message: "bytes"
coin_name: "str"
script_type: "InputScriptType"
no_script_type: "bool | None"

def __init__(
self,
Expand All @@ -534,6 +535,7 @@ def __init__(
address_n: "list[int] | None" = None,
coin_name: "str | None" = None,
script_type: "InputScriptType | None" = None,
no_script_type: "bool | None" = None,
) -> None:
pass

Expand Down
28 changes: 10 additions & 18 deletions core/src/trezor/ui/layouts/tt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
AskPaginated,
Paginated,
paginate_paragraphs,
paginate_text,
)
from ...components.tt.text import LINE_WIDTH_PAGINATED, Span, Text
from ...constants.tt import (
Expand Down Expand Up @@ -983,33 +982,26 @@ async def confirm_sign_identity(


async def confirm_signverify(
ctx: wire.GenericContext, coin: str, message: str, address: str | None = None
ctx: wire.GenericContext, coin: str, message: str, address: str, verify: bool
) -> None:
if address:
if verify:
header = f"Verify {coin} message"
font = ui.MONO
br_type = "verify_message"

text = Text(header, new_lines=False)
text.bold("Confirm address:\n")
text.mono(*chunks_intersperse(address, MONO_ADDR_PER_LINE))
await raise_if_cancelled(
interact(ctx, Confirm(text), br_type, ButtonRequestType.Other)
)
else:
header = f"Sign {coin} message"
font = ui.NORMAL
br_type = "sign_message"

text = Text(header, new_lines=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be using confirm_address() layout

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...i wanted to make an issue to fix consistency of this, but it's probably not worth it while we expect to move to Rust UI.

text.bold("Confirm address:\n")
text.mono(*chunks_intersperse(address, MONO_ADDR_PER_LINE))
await raise_if_cancelled(
interact(
ctx,
paginate_text(message, header, font=font),
br_type,
ButtonRequestType.Other,
)
interact(ctx, Confirm(text), br_type, ButtonRequestType.Other)
)

para = [(ui.BOLD, "Confirm message:"), (ui.MONO, message)]
content = paginate_paragraphs(para, header)
await raise_if_cancelled(interact(ctx, content, br_type, ButtonRequestType.Other))


async def show_popup(
title: str,
Expand Down
1 change: 1 addition & 0 deletions legacy/firmware/.changelog.d/1586.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support no_script_type option in SignMessage.
1 change: 1 addition & 0 deletions legacy/firmware/.changelog.d/1586.added.1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Show address confirmation in SignMessage.
1 change: 1 addition & 0 deletions legacy/firmware/.changelog.d/1586.added.2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement pagination in SignMessage and VerifyMessage.
35 changes: 20 additions & 15 deletions legacy/firmware/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,28 +146,33 @@ static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message,
}

int cryptoMessageSign(const CoinInfo *coin, HDNode *node,
InputScriptType script_type, const uint8_t *message,
size_t message_len, uint8_t *signature) {
InputScriptType script_type, bool no_script_type,
const uint8_t *message, size_t message_len,
uint8_t *signature) {
uint8_t hash[HASHER_DIGEST_LENGTH] = {0};
cryptoMessageHash(coin, message, message_len, hash);

uint8_t pby = 0;
int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL);
if (result == 0) {
switch (script_type) {
case InputScriptType_SPENDP2SHWITNESS:
// segwit-in-p2sh
signature[0] = 35 + pby;
break;
case InputScriptType_SPENDWITNESS:
// segwit
signature[0] = 39 + pby;
break;
default:
// p2pkh
signature[0] = 31 + pby;
break;
uint8_t script_type_info = 0;
if (!no_script_type) {
switch (script_type) {
case InputScriptType_SPENDP2SHWITNESS:
// segwit-in-p2sh
script_type_info = 4;
break;
case InputScriptType_SPENDWITNESS:
// segwit
script_type_info = 8;
break;
default:
// p2pkh
script_type_info = 0;
break;
}
}
signature[0] = 31 + pby + script_type_info;
}
return result;
}
Expand Down
5 changes: 3 additions & 2 deletions legacy/firmware/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ int signifyMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
uint8_t *signature);

int cryptoMessageSign(const CoinInfo *coin, HDNode *node,
InputScriptType script_type, const uint8_t *message,
size_t message_len, uint8_t *signature);
InputScriptType script_type, bool no_script_type,
const uint8_t *message, size_t message_len,
uint8_t *signature);

int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message,
size_t message_len, const char *address,
Expand Down
10 changes: 0 additions & 10 deletions legacy/firmware/ethereum.c
Original file line number Diff line number Diff line change
Expand Up @@ -905,16 +905,6 @@ static void ethereum_message_hash(const uint8_t *message, size_t message_len,

void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node,
EthereumMessageSignature *resp) {
uint8_t pubkeyhash[20] = {0};
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) {
return;
}

resp->address[0] = '0';
resp->address[1] = 'x';
ethereum_address_checksum(pubkeyhash, resp->address + 2, false, 0);
// ethereum_address_checksum adds trailing zero

uint8_t hash[32] = {0};
ethereum_message_hash(msg->message.bytes, msg->message.size, hash);

Expand Down
43 changes: 43 additions & 0 deletions legacy/firmware/fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,49 @@ static bool fsm_layoutAddress(const char *address, const char *desc,
}
}

static bool fsm_layoutPaginated(const char *description, const uint8_t *msg,
uint32_t len, bool is_ascii) {
const char **str = NULL;
const uint32_t row_len = is_ascii ? 18 : 8;
do {
const uint32_t show_len = MIN(len, row_len * 4);
if (is_ascii) {
str = split_message(msg, show_len, row_len);
} else {
str = split_message_hex(msg, show_len);
}

msg += show_len;
len -= show_len;

const char *label = len > 0 ? _("Next") : _("Confirm");
layoutDialogSwipeEx(&bmp_icon_question, _("Cancel"), label, description,
str[0], str[1], str[2], str[3], NULL, NULL, FONT_FIXED);

if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
return false;
}
} while (len > 0);

return true;
}

bool fsm_layoutSignMessage(const uint8_t *msg, uint32_t len) {
if (is_valid_ascii(msg, len)) {
return fsm_layoutPaginated(_("Sign message?"), msg, len, true);
} else {
return fsm_layoutPaginated(_("Sign binary message?"), msg, len, false);
}
}

bool fsm_layoutVerifyMessage(const uint8_t *msg, uint32_t len) {
if (is_valid_ascii(msg, len)) {
return fsm_layoutPaginated(_("Verified message?"), msg, len, true);
} else {
return fsm_layoutPaginated(_("Verified binary message?"), msg, len, false);
}
}

void fsm_msgRebootToBootloader(void) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you want to"), _("restart device in"),
Expand Down
3 changes: 3 additions & 0 deletions legacy/firmware/fsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,7 @@ void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg);

void fsm_msgRebootToBootloader(void);

bool fsm_layoutSignMessage(const uint8_t *msg, uint32_t len);
bool fsm_layoutVerifyMessage(const uint8_t *msg, uint32_t len);

#endif
59 changes: 34 additions & 25 deletions legacy/firmware/fsm_msg_coin.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,6 @@ void fsm_msgSignMessage(const SignMessage *msg) {

CHECK_INITIALIZED

layoutSignMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}

CHECK_PIN

const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
Expand All @@ -271,23 +264,38 @@ void fsm_msgSignMessage(const SignMessage *msg) {
msg->address_n_count, NULL);
if (!node) return;

layoutProgressSwipe(_("Signing"), 0);
if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes,
msg->message.size, resp->signature.bytes) == 0) {
if (hdnode_fill_public_key(node) != 0) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive public key"));
layoutHome();
return;
}
if (hdnode_fill_public_key(node) != 0) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive public key"));
layoutHome();
return;
}

if (!compute_address(coin, msg->script_type, node, false, NULL,
resp->address)) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error computing address"));
layoutHome();
return;
}
if (!compute_address(coin, msg->script_type, node, false, NULL,
resp->address)) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error computing address"));
layoutHome();
return;
}

layoutVerifyAddress(coin, resp->address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}

if (!fsm_layoutSignMessage(msg->message.bytes, msg->message.size)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}

layoutProgressSwipe(_("Signing"), 0);
if (cryptoMessageSign(coin, node, msg->script_type, msg->no_script_type,
msg->message.bytes, msg->message.size,
resp->signature.bytes) == 0) {
resp->signature.size = 65;
msg_write(MessageType_MessageType_MessageSignature, resp);
} else {
Expand All @@ -310,12 +318,13 @@ void fsm_msgVerifyMessage(const VerifyMessage *msg) {
layoutHome();
return;
}
layoutVerifyMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {

if (!fsm_layoutVerifyMessage(msg->message.bytes, msg->message.size)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}

fsm_sendSuccess(_("Message verified"));
} else {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature"));
Expand Down
Loading