1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-12 09:28:10 +00:00

feat(signing): show and verify label when signing

This commit is contained in:
Tomas Martykan 2024-12-10 14:57:26 +01:00
parent 3da09ff85e
commit ec36da26fd
No known key found for this signature in database
4 changed files with 57 additions and 1 deletions

View File

@ -356,6 +356,10 @@ message TxAck {
optional bytes orig_hash = 10; // tx_hash of the original transaction where this output was present (used when creating a replacement transaction)
optional uint32 orig_index = 11; // index of the output in the original transaction (used when creating a replacement transaction)
optional uint32 payment_req_index = 12 [(experimental_field)=true]; // index of the PaymentRequest containing this output
optional string label = 13; // label stored in Suite
optional bytes label_sig = 14; // sig(label|label_pk) stored in Suite, previously computed by Trezor
optional string label_pk = 15; // pubkey of the contact corresponding to the label
optional bytes address_pk_sig = 16; // signature of the address (signed by the receiver)
}
}
}

View File

@ -181,6 +181,41 @@ class BasicApprover(Approver):
await super()._add_output(txo, script_pubkey)
async def confirm_output_label(self, txo: TxOutput) -> None:
from trezor.crypto.curve import secp256k1
from apps.common.signverify import message_digest
from apps.bitcoin.addresses import address_pkh
from apps.bitcoin.keychain import get_keychain_for_coin
from apps.common import coins
coin_testnet = coins.by_name("Testnet")
# Derive master public key
FIRST_TESTNET_ADDRESS_PATH = [2147483692, 2147483649, 2147483648, 0, 0]
keychain_testnet = await get_keychain_for_coin(coin_testnet)
master_node = keychain_testnet.derive(FIRST_TESTNET_ADDRESS_PATH)
master_pk = master_node.public_key()
if not txo.label or not txo.label_sig:
raise DataError("Missing label or label signature.")
# Verify that txo.label_sig matches label_message signed by my master key
label_message = txo.label + "/" + (txo.label_pk or txo.address)
label_message_digest = message_digest(coin_testnet, label_message.encode())
if not secp256k1.verify(master_pk, txo.label_sig, label_message_digest):
raise DataError("Invalid signature of label.")
# Verify that txo.address_pk_sig matches txo.address signed by txo.label_pk
if txo.label_pk and txo.address_pk_sig:
address_digest = message_digest(self.coin, txo.address.encode())
address_pk_sig_rec = secp256k1.verify_recover(txo.address_pk_sig, address_digest)
if txo.label_pk != address_pkh(address_pk_sig_rec, coin_testnet):
raise DataError("Invalid signature of address.")
elif not txo.label_pk and not txo.address_pk_sig:
pass
else:
raise DataError("Both label public key and address public key signature must be present.")
async def add_change_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
await super().add_change_output(txo, script_pubkey)
self.change_count += 1
@ -196,6 +231,9 @@ class BasicApprover(Approver):
await super().add_external_output(txo, script_pubkey, tx_info, orig_txo)
if txo.label:
await self.confirm_output_label(txo)
if orig_txo:
if txo.amount < orig_txo.amount:
# Replacement transactions may need to decrease the value of external outputs to

View File

@ -96,7 +96,9 @@ async def confirm_output(
title = None
address_label = None
if output.address_n and not output.multisig:
if output.label:
address_label = output.label
elif output.address_n and not output.multisig:
from trezor import utils
# Showing the account string only for model_tr layout

View File

@ -2046,6 +2046,10 @@ class TxOutputType(protobuf.MessageType):
10: protobuf.Field("orig_hash", "bytes", repeated=False, required=False, default=None),
11: protobuf.Field("orig_index", "uint32", repeated=False, required=False, default=None),
12: protobuf.Field("payment_req_index", "uint32", repeated=False, required=False, default=None),
13: protobuf.Field("label", "string", repeated=False, required=False, default=None),
14: protobuf.Field("label_sig", "bytes", repeated=False, required=False, default=None),
15: protobuf.Field("label_pk", "string", repeated=False, required=False, default=None),
16: protobuf.Field("address_pk_sig", "bytes", repeated=False, required=False, default=None),
}
def __init__(
@ -2060,6 +2064,10 @@ class TxOutputType(protobuf.MessageType):
orig_hash: Optional["bytes"] = None,
orig_index: Optional["int"] = None,
payment_req_index: Optional["int"] = None,
label: Optional["str"] = None,
label_sig: Optional["bytes"] = None,
label_pk: Optional["str"] = None,
address_pk_sig: Optional["bytes"] = None,
) -> None:
self.address_n: Sequence["int"] = address_n if address_n is not None else []
self.amount = amount
@ -2070,6 +2078,10 @@ class TxOutputType(protobuf.MessageType):
self.orig_hash = orig_hash
self.orig_index = orig_index
self.payment_req_index = payment_req_index
self.label = label
self.label_sig = label_sig
self.label_pk = label_pk
self.address_pk_sig = address_pk_sig
class PaymentRequestMemo(protobuf.MessageType):