Updated Ragger app client for domain names & sign APDUs

This commit is contained in:
Alexandre Paillier
2023-03-10 16:40:34 +01:00
parent 0336f3fcf0
commit c2eae8a7a2
8 changed files with 153 additions and 4 deletions

View File

@@ -2,12 +2,33 @@ from enum import IntEnum, auto
from typing import Optional
from ragger.backend import BackendInterface
from ragger.utils import RAPDU
from ragger.navigator import NavInsID, NavIns, NanoNavigator
from .command_builder import EthereumCmdBuilder
from .setting import SettingType, SettingImpl
from .eip712 import EIP712FieldType
from .response_parser import EthereumRespParser
from .tlv import format_tlv
import signal
import time
from pathlib import Path
import keychain
import rlp
ROOT_SCREENSHOT_PATH = Path(__file__).parent.parent
WEI_IN_ETH = 1e+18
class DOMAIN_NAME_TAG(IntEnum):
STRUCTURE_TYPE = 0x01
STRUCTURE_VERSION = 0x02
CHALLENGE = 0x12
SIGNER_KEY_ID = 0x13
SIGNER_ALGO = 0x14
SIGNATURE = 0x15
DOMAIN_NAME = 0x20
COIN_TYPE = 0x21
ADDRESS = 0x22
class EthereumClient:
@@ -23,15 +44,20 @@ class EthereumClient:
),
SettingType.VERBOSE_EIP712: SettingImpl(
[ "nanox", "nanosp" ]
),
SettingType.VERBOSE_ENS: SettingImpl(
[ "nanox", "nanosp" ]
)
}
_click_delay = 1/4
_eip712_filtering = False
def __init__(self, client: BackendInterface):
def __init__(self, client: BackendInterface, golden_run: bool):
self._client = client
self._chain_id = 1
self._cmd_builder = EthereumCmdBuilder()
self._resp_parser = EthereumRespParser()
self._nav = NanoNavigator(client, client.firmware, golden_run)
signal.signal(signal.SIGALRM, self._click_signal_timeout)
for setting in self._settings.values():
setting.value = False
@@ -156,3 +182,61 @@ class EthereumClient:
with self._send(self._cmd_builder.eip712_filtering_show_field(name, sig)):
pass
assert self._recv().status == 0x9000
def send_fund(self,
bip32_path: str,
nonce: int,
gas_price: int,
gas_limit: int,
to: bytes,
amount: float,
chain_id: int,
screenshot_collection: str = None):
data = list()
data.append(nonce)
data.append(gas_price)
data.append(gas_limit)
data.append(to)
data.append(int(amount * WEI_IN_ETH))
data.append(bytes())
data.append(chain_id)
data.append(bytes())
data.append(bytes())
for chunk in self._cmd_builder.sign(bip32_path, rlp.encode(data)):
with self._send(chunk):
nav_ins = NavIns(NavInsID.RIGHT_CLICK)
final_ins = [ NavIns(NavInsID.BOTH_CLICK) ]
target_text = "and send"
if screenshot_collection:
self._nav.navigate_until_text_and_compare(nav_ins,
final_ins,
target_text,
ROOT_SCREENSHOT_PATH,
screenshot_collection)
else:
self._nav.navigate_until_text(nav_ins,
final_ins,
target_text)
def get_challenge(self) -> int:
with self._send(self._cmd_builder.get_challenge()):
pass
resp = self._recv()
return self._resp_parser.challenge(resp.data)
def provide_domain_name(self, challenge: int, name: str, addr: bytes):
payload = format_tlv(DOMAIN_NAME_TAG.STRUCTURE_TYPE, 3) # TrustedDomainName
payload += format_tlv(DOMAIN_NAME_TAG.STRUCTURE_VERSION, 1)
payload += format_tlv(DOMAIN_NAME_TAG.SIGNER_KEY_ID, 0) # test key
payload += format_tlv(DOMAIN_NAME_TAG.SIGNER_ALGO, 1) # secp256k1
payload += format_tlv(DOMAIN_NAME_TAG.CHALLENGE, challenge)
payload += format_tlv(DOMAIN_NAME_TAG.COIN_TYPE, 0x3c) # ETH in slip-44
payload += format_tlv(DOMAIN_NAME_TAG.DOMAIN_NAME, name)
payload += format_tlv(DOMAIN_NAME_TAG.ADDRESS, addr)
payload += format_tlv(DOMAIN_NAME_TAG.SIGNATURE,
keychain.sign_data(keychain.Key.DOMAIN_NAME, payload))
for chunk in self._cmd_builder.provide_domain_name(payload):
with self._send(chunk):
pass