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:
parent
3da09ff85e
commit
ec36da26fd
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
12
python/src/trezorlib/messages.py
generated
12
python/src/trezorlib/messages.py
generated
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user