Skip to content

Commit

Permalink
pubkey
Browse files Browse the repository at this point in the history
  • Loading branch information
cedelavergne-ledger committed Dec 11, 2024
1 parent 2acaab7 commit 6b3be4e
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 29 deletions.
16 changes: 11 additions & 5 deletions tests/application_client/command_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from ragger.bip import pack_derivation_path

from input_files.derive_address import DeriveAddressTestCase
from input_files.pubkey import PubKeyTestCase
from input_files.cvote import MAX_CIP36_PAYLOAD_SIZE, CVoteTestCase
from input_files.signOpCert import OpCertTestCase
from input_files.signMsg import SignMsgTestCase, MessageAddressFieldType
Expand Down Expand Up @@ -40,6 +39,9 @@ class P1Type(IntEnum):
# Derive Address
P1_RETURN = 0x01
P1_DISPLAY = 0x02
# Get Pub Key
P1_KEY_INIT = 0x00
P1_KEY_NEXT = 0x01
# Sign CIP36 Vote
P1_INIT = 0x01
P1_CHUNK = 0x02
Expand Down Expand Up @@ -149,19 +151,23 @@ def derive_address(self, p1: P1Type, testCase: DeriveAddressTestCase) -> bytes:
return self._serialize(InsType.DERIVE_PUBLIC_ADDR, p1, 0x00, data)


def get_pubkey(self, testCase: PubKeyTestCase) -> bytes:
def get_pubkey(self, p1: P1Type, path: str, remainingKeysData: int = 0) -> bytes:
"""APDU Builder for Public Key
Args:
testCase (PubKeyTestCase): Test parameters
p1 (P1Type): APDU Parameter 1
path (str): Test parameters
remainingKeysData (int): Nb of remaining paths
Returns:
Response APDU
"""

data = bytes()
data += pack_derivation_path(testCase.path)
return self._serialize(InsType.GET_PUBLIC_ADDR, 0x00, 0x00, data)
data += pack_derivation_path(path)
if remainingKeysData > 0:
data += remainingKeysData.to_bytes(4, "big")
return self._serialize(InsType.GET_PUBLIC_ADDR, p1, 0x00, data)


def sign_cip36_init(self, testCase: CVoteTestCase) -> bytes:
Expand Down
19 changes: 11 additions & 8 deletions tests/application_client/command_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from ragger.backend.interface import BackendInterface, RAPDU

from input_files.derive_address import DeriveAddressTestCase
from input_files.pubkey import PubKeyTestCase
from input_files.cvote import CVoteTestCase
from input_files.signOpCert import OpCertTestCase
from input_files.signMsg import SignMsgTestCase
Expand Down Expand Up @@ -139,31 +138,35 @@ def derive_address(self, p1: P1Type, testCase: DeriveAddressTestCase) -> RAPDU:


@contextmanager
def get_pubkey_async(self, testCase: PubKeyTestCase) -> Generator[None, None, None]:
def get_pubkey_async(self, p1: P1Type, path: str, remainingKeysData: int = 0) -> Generator[None, None, None]:
"""APDU Get Public Key
Args:
testCase (PubKeyTestCase): Test parameters
p1 (P1Type): APDU Parameter 1
testCase (str): Test parameters
remainingKeysData (int): Nb of remaining paths
Returns:
Generator
"""

with self._exchange_async(self._cmd_builder.get_pubkey(testCase)):
with self._exchange_async(self._cmd_builder.get_pubkey(p1, path, remainingKeysData)):
yield


def get_pubkey(self, testCase: PubKeyTestCase) -> RAPDU:
def get_pubkey(self, p1: P1Type, path: str, remainingKeysData: int = 0) -> RAPDU:
"""APDU Get Public Key
Args:
testCase (PubKeyTestCase): Test parameters
p1 (P1Type): APDU Parameter 1
testCase (str): Test parameters
remainingKeysData (int): Nb of remaining paths
Returns:
Response APDU
path APDU
"""

return self._exchange(self._cmd_builder.get_pubkey(testCase))
return self._exchange(self._cmd_builder.get_pubkey(p1, path, remainingKeysData))


@contextmanager
Expand Down
42 changes: 33 additions & 9 deletions tests/input_files/pubkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

from dataclasses import dataclass
from typing import Optional


@dataclass
Expand All @@ -18,14 +19,17 @@ class PubKeyTestCase:
name: str
path: str
expected: expectedPubKey
nav: Optional[bool] = True
nav_with_several: Optional[bool] = True


# pylint: disable=line-too-long
byronTestCases = [
PubKeyTestCase("byron/path 1",
"m/44'/1815'/1'",
expectedPubKey("eb6e933ce45516ac7b0e023de700efae5e212ccc6bf0fcb33ba9243b9d832827",
"0b161cb11babe1f56c3f9f1cbbb7b6d2d13eeb3efa67205198a69b8d81885354")),
"0b161cb11babe1f56c3f9f1cbbb7b6d2d13eeb3efa67205198a69b8d81885354"),
nav_with_several=False),
PubKeyTestCase("byron/path 2",
"m/44'/1815'/1'/0/55'",
expectedPubKey("83220849a3ada3e95495e22b24aee95c3120d4c8a9faafed312914769e65b70d",
Expand All @@ -44,30 +48,42 @@ class PubKeyTestCase:
]

testsShelleyUsual = [
PubKeyTestCase("shelley usual/path 0",
"m/1852'/1815'/4'",
expectedPubKey("4e4353d7cc6f49e8e7a281e08a7672d000d4abfdf07be299cbff95d6a05df224",
"cbc28c222a6c15c0cfe98434f97b3aef860b5ce6902e177820adbd70ed7dc2ec"),
False,
False),
PubKeyTestCase("shelley usual/path 1",
"m/1852'/1815'/0'/0/1",
expectedPubKey("b3d5f4158f0c391ee2a28a2e285f218f3e895ff6ff59cb9369c64b03b5bab5eb",
"27e1d1f3a3d0fafc0884e02a2d972e7e5b1be8a385ecc1bc75a977b4073dbd08")),
"27e1d1f3a3d0fafc0884e02a2d972e7e5b1be8a385ecc1bc75a977b4073dbd08"),
nav_with_several=False),
PubKeyTestCase("shelley usual/path 2",
"m/1852'/1815'/0'/2/0",
expectedPubKey("66610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8",
"e977e956d29810dbfbda9c8ea667585982454e401c68578623d4b86bc7eb7b58")),
"e977e956d29810dbfbda9c8ea667585982454e401c68578623d4b86bc7eb7b58"),
nav_with_several=False),
PubKeyTestCase("shelley usual/path 3",
"m/1852'/1815'/0'/2/1001",
expectedPubKey("dbc5fbbe47eabc036c6834ea62c011b15272ec85a17facd3670cd9304486ffe8",
"fb037474fc75e64745f7fd9f44b4bcbc58d81cae2209f2f5c1f77501e9bb43df")),
"fb037474fc75e64745f7fd9f44b4bcbc58d81cae2209f2f5c1f77501e9bb43df"),
nav_with_several=False),
PubKeyTestCase("shelley usual/path 4",
"m/1852'/1815'/0'/3/0",
expectedPubKey("7cc18df2fbd3ee1b16b76843b18446679ab95dbcd07b7833b66a9407c0709e37",
"01d881e1c04fed8defa9a3e8bd3cf85bd975f813ff8eb622d20a4375a07d6bc9")),
"01d881e1c04fed8defa9a3e8bd3cf85bd975f813ff8eb622d20a4375a07d6bc9"),
nav_with_several=False),
PubKeyTestCase("shelley usual/path 5",
"m/1852'/1815'/0'/4/0",
expectedPubKey("bc8c8a37d6ab41339bb073e72ce2e776cefed98d1a6d070ea5fada80dc7d6737",
"6f58406a51d33bb35e98884cbadced9bc94f65a752001ad5f4788af07b2ec0fe")),
"6f58406a51d33bb35e98884cbadced9bc94f65a752001ad5f4788af07b2ec0fe"),
nav_with_several=False),
PubKeyTestCase("shelley usual/path 6",
"m/1852'/1815'/1'/5/0",
expectedPubKey("624142a80217b95ca2fc5b0c1f8d74e26e5683621c430c7bc7eebca6ee541a58",
"92a8c64cfdf1af08e78c2ba59bef496eb34ddf24bdf0f91404a962415a7a0810")),
"92a8c64cfdf1af08e78c2ba59bef496eb34ddf24bdf0f91404a962415a7a0810"),
nav_with_several=False),
]

testsShelleyUnusual = [
Expand Down Expand Up @@ -115,11 +131,19 @@ class PubKeyTestCase:
PubKeyTestCase("CVote keys/path 1",
"m/1694'/1815'/0'/0/1",
expectedPubKey("aac861247bd24cae705bca1d1c9763f19c19188fb0faf257c50ed69b8157bced",
"f23595dd3207b7dde477347fa25d3fd6291c3363df43b54a9cf523d2c7683c10")),
"f23595dd3207b7dde477347fa25d3fd6291c3363df43b54a9cf523d2c7683c10"),
nav_with_several=False),
PubKeyTestCase("CVote keys/path 2",
"m/1694'/1815'/100'",
expectedPubKey("ff451db773898b80488d892b248acdc634f6ec79d923f12aae9feb2563513b63",
"47478097ef56dcef686f8dcbd7d0c1d073740cde65a48e5615799096f67a144f"),
False,
False),
PubKeyTestCase("CVote keys/path 3",
"m/1694'/1815'/101'",
expectedPubKey("c7adc69b6dd29c48d29edb089c1aecbe218fdb9cfa59c325afcd2c5fa3844be1",
"ffa9953f6c77fccc15c000db494177d84e218f2740ddd44cfcbea0455cc6a6be")),
"ffa9953f6c77fccc15c000db494177d84e218f2740ddd44cfcbea0455cc6a6be"),
nav_with_several=True),
]

rejectTestCases = [
Expand Down
68 changes: 61 additions & 7 deletions tests/test_pubkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
This module provides Ragger tests for Public Key check
"""

from typing import List
import pytest

from ragger.backend import BackendInterface
Expand All @@ -15,6 +16,7 @@

from application_client.app_def import Errors
from application_client.command_sender import CommandSender
from application_client.command_builder import P1Type

from input_files.pubkey import PubKeyTestCase, expectedPubKey
from input_files.pubkey import rejectTestCases, testsShelleyUsualNoConfirm, testsCVoteKeysNoConfirm
Expand Down Expand Up @@ -44,12 +46,14 @@ def test_pubkey_confirm(firmware: Firmware,
valid_instr = [NavInsID.BOTH_CLICK]

# Send the APDU
with client.get_pubkey_async(testCase):
if firmware.is_nano:
navigator.navigate_until_text(nav_inst, valid_instr, "Confirm")
with client.get_pubkey_async(P1Type.P1_KEY_INIT, testCase.path):
if testCase.nav:
if firmware.is_nano:
navigator.navigate_until_text(nav_inst, valid_instr, "Confirm")
else:
scenario_navigator.address_review_approve(do_comparison=False)
else:
scenario_navigator.address_review_approve(do_comparison=False)

pass
# Check the status (Asynchronous)
response = client.get_async_response()
assert response and response.status == Errors.SW_SUCCESS
Expand All @@ -58,6 +62,56 @@ def test_pubkey_confirm(firmware: Firmware,
_check_pubkey_result(response.data, testCase.path, testCase.expected)


@pytest.mark.parametrize(
"testCase",
[
(byronTestCases + testsShelleyUsual + testsColdKeys + testsCVoteKeys),
(testsShelleyUnusual + byronTestCases + testsColdKeys + testsShelleyUsual),
],
)
def test_pubkey_several(firmware: Firmware,
backend: BackendInterface,
navigator: Navigator,
scenario_navigator: NavigateWithScenario,
testCase: List[PubKeyTestCase]) -> None:
"""Check Several Public Key with confirmation"""

# Use the app interface instead of raw interface
client = CommandSender(backend)
if firmware.is_nano:
nav_inst = NavInsID.BOTH_CLICK
if firmware == Firmware.NANOS:
valid_instr = [NavInsID.RIGHT_CLICK]
else:
valid_instr = [NavInsID.BOTH_CLICK]
else:
valid_instr = [NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM]
p1 = P1Type.P1_KEY_INIT
remainingKeysData = len(testCase) - 1
for test in testCase:
# Send the APDU
with client.get_pubkey_async(p1, test.path, remainingKeysData):
if p1 == P1Type.P1_KEY_INIT:
navigator.navigate(valid_instr,
screen_change_after_last_instruction=False)
if test.nav_with_several:
if firmware.is_nano:
navigator.navigate_until_text(nav_inst, valid_instr, "Confirm")
else:
scenario_navigator.address_review_approve(do_comparison=False)
else:
pass
# Check the status (Asynchronous)
response = client.get_async_response()
assert response and response.status == Errors.SW_SUCCESS

# Check the response
_check_pubkey_result(response.data, test.path, test.expected)

remainingKeysData = 0
p1 = P1Type.P1_KEY_NEXT


@pytest.mark.parametrize(
"testCase",
testsShelleyUsualNoConfirm + testsCVoteKeysNoConfirm,
Expand All @@ -70,7 +124,7 @@ def test_pubkey(backend: BackendInterface, testCase: PubKeyTestCase) -> None:
client = CommandSender(backend)

# Send the APDU
response = client.get_pubkey(testCase)
response = client.get_pubkey(P1Type.P1_KEY_INIT, testCase.path)

# Check the status
assert response and response.status == Errors.SW_SUCCESS
Expand All @@ -93,7 +147,7 @@ def test_pubkey_reject(backend: BackendInterface,

with pytest.raises(ExceptionRAPDU) as err:
# Send the APDU
client.get_pubkey(testCase)
client.get_pubkey(P1Type.P1_KEY_INIT, testCase.path)
assert err.value.status == Errors.SW_REJECTED_BY_POLICY


Expand Down

0 comments on commit 6b3be4e

Please sign in to comment.