Skip to content

Commit 3a2354b

Browse files
Merge pull request #699 from LedgerHQ/feat/apa/gcs
Generic clear-signing
2 parents 2ae8e0d + 6743966 commit 3a2354b

File tree

195 files changed

+8414
-209
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

195 files changed

+8414
-209
lines changed

client/src/ledger_app_clients/ethereum/client.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ class PKIPubKeyUsage(IntEnum):
7777
PUBKEY_USAGE_SEED_ID_AUTH = 0x09
7878

7979

80+
class SignMode(IntEnum):
81+
BASIC = 0x00
82+
STORE = 0x01
83+
START_FLOW = 0x02
84+
85+
8086
class PKIClient:
8187
_CLA: int = 0xB0
8288
_INS: int = 0x06
@@ -130,6 +136,15 @@ def send_raw(self, cla: int, ins: int, p1: int, p2: int, payload: bytes):
130136
header.append(len(payload))
131137
return self._exchange(header + payload)
132138

139+
def send_raw_async(self, cla: int, ins: int, p1: int, p2: int, payload: bytes):
140+
header = bytearray()
141+
header.append(cla)
142+
header.append(ins)
143+
header.append(p1)
144+
header.append(p2)
145+
header.append(len(payload))
146+
return self._exchange_async(header + payload)
147+
133148
def eip712_send_struct_def_struct_name(self, name: str):
134149
return self._exchange_async(self._cmd_builder.eip712_send_struct_def_struct_name(name))
135150

@@ -211,7 +226,8 @@ def eip712_filtering_raw(self, name: str, sig: bytes, discarded: bool):
211226

212227
def sign(self,
213228
bip32_path: str,
214-
tx_params: dict):
229+
tx_params: dict,
230+
mode: SignMode = SignMode.BASIC):
215231
tx = Web3().eth.account.create().sign_transaction(tx_params).rawTransaction
216232
prefix = bytes()
217233
suffix = []
@@ -223,7 +239,7 @@ def sign(self,
223239
suffix = [int(tx_params["chainId"]), bytes(), bytes()]
224240
decoded = rlp.decode(tx)[:-3] # remove already computed signature
225241
tx = prefix + rlp.encode(decoded + suffix)
226-
chunks = self._cmd_builder.sign(bip32_path, tx, suffix)
242+
chunks = self._cmd_builder.sign(bip32_path, tx, mode)
227243
for chunk in chunks[:-1]:
228244
self._exchange(chunk)
229245
return self._exchange_async(chunks[-1])
@@ -530,3 +546,15 @@ def provide_network_information(self,
530546
assert response.status == StatusWord.OK
531547
response = self._exchange(chunks[-1])
532548
assert response.status == StatusWord.OK
549+
550+
def provide_enum_value(self, payload: bytes) -> RAPDU:
551+
chunks = self._cmd_builder.provide_enum_value(payload)
552+
for chunk in chunks[:-1]:
553+
self._exchange(chunk)
554+
return self._exchange(chunks[-1])
555+
556+
def provide_transaction_info(self, payload: bytes) -> RAPDU:
557+
chunks = self._cmd_builder.provide_transaction_info(payload)
558+
for chunk in chunks[:-1]:
559+
self._exchange(chunk)
560+
return self._exchange(chunks[-1])

client/src/ledger_app_clients/ethereum/command_builder.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class InsType(IntEnum):
1515
SIGN = 0x04
1616
PERSONAL_SIGN = 0x08
1717
PROVIDE_ERC20_TOKEN_INFORMATION = 0x0a
18+
EXTERNAL_PLUGIN_SETUP = 0x12
1819
PROVIDE_NFT_INFORMATION = 0x14
1920
SET_PLUGIN = 0x16
2021
PERFORM_PRIVACY_OPERATION = 0x18
@@ -24,7 +25,8 @@ class InsType(IntEnum):
2425
EIP712_SIGN = 0x0c
2526
GET_CHALLENGE = 0x20
2627
PROVIDE_TRUSTED_NAME = 0x22
27-
EXTERNAL_PLUGIN_SETUP = 0x12
28+
PROVIDE_ENUM_VALUE = 0x24
29+
PROVIDE_TRANSACTION_INFO = 0x26
2830
PROVIDE_NETWORK_INFORMATION = 0x30
2931

3032

@@ -261,15 +263,15 @@ def set_external_plugin(self, plugin_name: str, contract_address: bytes, selecto
261263
0x00,
262264
data)
263265

264-
def sign(self, bip32_path: str, rlp_data: bytes, vrs: list) -> list[bytes]:
266+
def sign(self, bip32_path: str, rlp_data: bytes, p2: int) -> list[bytes]:
265267
apdus = list()
266268
payload = pack_derivation_path(bip32_path)
267269
payload += rlp_data
268270
p1 = P1Type.SIGN_FIRST_CHUNK
269271
while len(payload) > 0:
270272
apdus.append(self._serialize(InsType.SIGN,
271273
p1,
272-
0x00,
274+
p2,
273275
payload[:0xff]))
274276
payload = payload[0xff:]
275277
p1 = P1Type.SIGN_SUBSQT_CHUNK
@@ -427,3 +429,23 @@ def provide_network_information(self,
427429
icon = icon[0xff:]
428430
p1 = P1Type.FOLLOWING_CHUNK
429431
return chunks
432+
433+
def common_tlv_serialize(self, tlv_payload: bytes, ins: InsType) -> list[bytes]:
434+
chunks = list()
435+
payload = struct.pack(">H", len(tlv_payload))
436+
payload += tlv_payload
437+
p1 = 1
438+
while len(payload) > 0:
439+
chunks.append(self._serialize(ins,
440+
p1,
441+
0x00,
442+
payload[:0xff]))
443+
payload = payload[0xff:]
444+
p1 = 0
445+
return chunks
446+
447+
def provide_enum_value(self, tlv_payload: bytes) -> list[bytes]:
448+
return self.common_tlv_serialize(tlv_payload, InsType.PROVIDE_ENUM_VALUE)
449+
450+
def provide_transaction_info(self, tlv_payload: bytes) -> list[bytes]:
451+
return self.common_tlv_serialize(tlv_payload, InsType.PROVIDE_TRANSACTION_INFO)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from enum import IntEnum
2+
from typing import Optional
3+
from .tlv import format_tlv
4+
from .keychain import sign_data, Key
5+
6+
7+
class Tag(IntEnum):
8+
VERSION = 0x00
9+
CHAIN_ID = 0x01
10+
CONTRACT_ADDR = 0x02
11+
SELECTOR = 0x03
12+
ID = 0x04
13+
VALUE = 0x05
14+
NAME = 0x06
15+
SIGNATURE = 0xff
16+
17+
18+
class EnumValue:
19+
version: int
20+
chain_id: int
21+
contract_addr: bytes
22+
selector: bytes
23+
id: int
24+
value: int
25+
name: str
26+
signature: Optional[bytes] = None
27+
28+
def __init__(self,
29+
version: int,
30+
chain_id: int,
31+
contract_addr: bytes,
32+
selector: bytes,
33+
id: int,
34+
value: int,
35+
name: str,
36+
signature: Optional[bytes] = None):
37+
self.version = version
38+
self.chain_id = chain_id
39+
self.contract_addr = contract_addr
40+
self.selector = selector
41+
self.id = id
42+
self.value = value
43+
self.name = name
44+
self.signature = signature
45+
46+
def serialize(self) -> bytes:
47+
payload = bytearray()
48+
payload += format_tlv(Tag.VERSION, self.version)
49+
payload += format_tlv(Tag.CHAIN_ID, self.chain_id)
50+
payload += format_tlv(Tag.CONTRACT_ADDR, self.contract_addr)
51+
payload += format_tlv(Tag.SELECTOR, self.selector)
52+
payload += format_tlv(Tag.ID, self.id)
53+
payload += format_tlv(Tag.VALUE, self.value)
54+
payload += format_tlv(Tag.NAME, self.name)
55+
sig = self.signature
56+
if sig is None:
57+
sig = sign_data(Key.CAL, payload)
58+
payload += format_tlv(Tag.SIGNATURE, sig)
59+
return payload

0 commit comments

Comments
 (0)