Files
app-ethereum/tests/ragger/test_blind_sign.py

208 lines
7.4 KiB
Python
Raw Normal View History

from pathlib import Path
2024-03-08 17:47:55 +01:00
import json
2024-06-24 18:05:24 +02:00
from typing import Optional
import pytest
2024-03-26 09:43:26 +01:00
from web3 import Web3
2024-03-08 17:47:55 +01:00
from ragger.backend import BackendInterface
from ragger.firmware import Firmware
from ragger.navigator import Navigator, NavInsID
from ragger.error import ExceptionRAPDU
2024-03-26 09:43:26 +01:00
from constants import ABIS_FOLDER
2024-03-08 17:47:55 +01:00
from client.client import EthAppClient, StatusWord
from client.settings import SettingID, settings_toggle
import client.response_parser as ResponseParser
from client.utils import recover_transaction
BIP32_PATH = "m/44'/60'/0'/0/0"
2024-06-24 18:05:24 +02:00
DEVICE_ADDR: Optional[bytes] = None
# TODO: do one test with nonce display
@pytest.fixture(name="sign", params=[True, False])
def sign_fixture(request) -> bool:
return request.param
2024-03-08 17:47:55 +01:00
2024-06-24 18:05:24 +02:00
def common_tx_params() -> dict:
2024-03-26 09:43:26 +01:00
with open(f"{ABIS_FOLDER}/erc20.json", encoding="utf-8") as file:
2024-03-08 17:47:55 +01:00
contract = Web3().eth.contract(
abi=json.load(file),
address=None
)
data = contract.encodeABI("approve", [
# Uniswap Protocol: Permit2
bytes.fromhex("000000000022d473030f116ddee9f6b43ac78ba3"),
Web3.to_wei("2", "ether")
])
2024-06-24 18:05:24 +02:00
return {
2024-03-08 17:47:55 +01:00
"nonce": 235,
"maxFeePerGas": Web3.to_wei(100, "gwei"),
"maxPriorityFeePerGas": Web3.to_wei(10, "gwei"),
"gas": 44001,
# Maker: Dai Stablecoin
"to": bytes.fromhex("6b175474e89094c44da98b954eedeac495271d0f"),
"data": data,
"chainId": 1
}
2024-06-24 18:05:24 +02:00
# Token approval, would require loading the "internal plugin" &
# providing the token metadata from the CAL
def test_blind_sign(firmware: Firmware,
backend: BackendInterface,
navigator: Navigator,
default_screenshot_path: Path,
test_name: str,
sign: bool):
global DEVICE_ADDR
app_client = EthAppClient(backend)
if DEVICE_ADDR is None:
with app_client.get_public_addr(bip32_path=BIP32_PATH, display=False):
2024-03-08 17:47:55 +01:00
pass
2024-06-24 18:05:24 +02:00
_, DEVICE_ADDR, _ = ResponseParser.pk_addr(app_client.response().data)
tx_params = common_tx_params()
try:
with app_client.sign(BIP32_PATH, tx_params):
if sign:
test_name += "_signed"
else:
test_name += "_rejected"
moves = []
if firmware.is_nano:
if firmware == Firmware.NANOS:
2024-06-24 18:05:24 +02:00
moves += [NavInsID.RIGHT_CLICK] * 2
else:
moves += [NavInsID.RIGHT_CLICK] * 4
if not sign:
moves += [NavInsID.RIGHT_CLICK]
moves += [NavInsID.BOTH_CLICK]
if sign:
if firmware == Firmware.NANOS:
2024-06-24 18:05:24 +02:00
moves += [NavInsID.RIGHT_CLICK] * 10
else:
moves += [NavInsID.RIGHT_CLICK] * 6
moves += [NavInsID.BOTH_CLICK]
else:
if firmware == Firmware.STAX:
2024-07-11 18:39:09 +02:00
tap_number = 2
else:
tap_number = 3
2024-06-24 18:05:24 +02:00
if sign:
moves += [NavInsID.USE_CASE_CHOICE_REJECT]
moves += [NavInsID.USE_CASE_CHOICE_CONFIRM]
moves += [NavInsID.SWIPE_CENTER_TO_LEFT] * tap_number
2024-06-24 18:05:24 +02:00
moves += [NavInsID.USE_CASE_REVIEW_CONFIRM]
else:
moves += [NavInsID.USE_CASE_CHOICE_CONFIRM]
navigator.navigate_and_compare(default_screenshot_path,
test_name,
moves)
except ExceptionRAPDU as e:
assert e.status == StatusWord.INVALID_DATA
else:
assert sign is True
# verify signature
vrs = ResponseParser.signature(app_client.response().data)
addr = recover_transaction(tx_params, vrs)
assert addr == DEVICE_ADDR
def test_blind_sign_reject_in_risk_review(firmware: Firmware,
backend: BackendInterface,
navigator: Navigator,
default_screenshot_path: Path,
test_name: str):
app_client = EthAppClient(backend)
2024-03-08 17:47:55 +01:00
if firmware.is_nano:
2024-06-24 18:05:24 +02:00
pytest.skip("Not supported on non-NBGL apps")
try:
with app_client.sign(BIP32_PATH, common_tx_params()):
moves = [NavInsID.USE_CASE_CHOICE_REJECT] * 2
navigator.navigate_and_compare(default_screenshot_path,
test_name,
moves)
except ExceptionRAPDU as e:
assert e.status == StatusWord.INVALID_DATA
2024-03-08 17:47:55 +01:00
else:
2024-06-24 18:05:24 +02:00
assert False # Should have thrown
# Token approval, would require loading the "internal plugin" &
# providing the token metadata from the CAL
def test_sign_parameter_selector(firmware: Firmware,
backend: BackendInterface,
navigator: Navigator,
test_name: str,
default_screenshot_path: Path):
2024-06-24 18:05:24 +02:00
global DEVICE_ADDR
app_client = EthAppClient(backend)
2024-06-24 18:05:24 +02:00
if DEVICE_ADDR is None:
with app_client.get_public_addr(bip32_path=BIP32_PATH, display=False):
pass
_, DEVICE_ADDR, _ = ResponseParser.pk_addr(app_client.response().data)
2024-06-24 18:05:24 +02:00
settings_toggle(firmware, navigator, [SettingID.DEBUG_DATA])
2024-06-24 18:05:24 +02:00
tx_params = common_tx_params()
data_len = len(bytes.fromhex(tx_params["data"][2:]))
# selector
flows = 1
data_len -= 4
# parameters
flows += data_len // 32
with app_client.sign(BIP32_PATH, tx_params):
2024-06-24 18:05:24 +02:00
moves = []
if firmware.is_nano:
if firmware == Firmware.NANOS:
2024-06-24 18:05:24 +02:00
moves += [NavInsID.RIGHT_CLICK] * 2 + [NavInsID.BOTH_CLICK]
# Parameters on Nano S are split on multiple pages, hardcoded because the two parameters don't use the
# same amount of pages because of non-monospace fonts
moves += [NavInsID.RIGHT_CLICK] * 4 + [NavInsID.BOTH_CLICK]
moves += [NavInsID.RIGHT_CLICK] * 3 + [NavInsID.BOTH_CLICK]
else:
moves += ([NavInsID.RIGHT_CLICK] * 2 + [NavInsID.BOTH_CLICK]) * flows
if firmware == Firmware.NANOS:
2024-06-24 18:05:24 +02:00
moves += [NavInsID.RIGHT_CLICK] * 2
else:
moves += [NavInsID.RIGHT_CLICK] * 4
moves += [NavInsID.BOTH_CLICK]
if firmware == Firmware.NANOS:
2024-06-24 18:05:24 +02:00
moves += [NavInsID.RIGHT_CLICK] * 9
else:
moves += [NavInsID.RIGHT_CLICK] * 5
moves += [NavInsID.BOTH_CLICK]
else:
if firmware == Firmware.STAX:
2024-07-11 18:39:09 +02:00
tap_number = 2
else:
tap_number = 3
moves += ([NavInsID.SWIPE_CENTER_TO_LEFT] * 2 + [NavInsID.USE_CASE_REVIEW_CONFIRM]) * flows
2024-06-24 18:05:24 +02:00
moves += [NavInsID.USE_CASE_CHOICE_REJECT]
moves += [NavInsID.USE_CASE_CHOICE_CONFIRM]
moves += [NavInsID.SWIPE_CENTER_TO_LEFT] * tap_number
2024-06-24 18:05:24 +02:00
moves += [NavInsID.USE_CASE_REVIEW_CONFIRM]
navigator.navigate_and_compare(default_screenshot_path,
test_name,
moves)
# verify signature
vrs = ResponseParser.signature(app_client.response().data)
addr = recover_transaction(tx_params, vrs)
assert addr == DEVICE_ADDR