Skip to content

Commit

Permalink
Merge pull request #699 from LedgerHQ/feat/apa/gcs
Browse files Browse the repository at this point in the history
Generic clear-signing
  • Loading branch information
apaillier-ledger authored Dec 19, 2024
2 parents 2ae8e0d + 6743966 commit 3a2354b
Show file tree
Hide file tree
Showing 195 changed files with 8,414 additions and 209 deletions.
32 changes: 30 additions & 2 deletions client/src/ledger_app_clients/ethereum/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ class PKIPubKeyUsage(IntEnum):
PUBKEY_USAGE_SEED_ID_AUTH = 0x09


class SignMode(IntEnum):
BASIC = 0x00
STORE = 0x01
START_FLOW = 0x02


class PKIClient:
_CLA: int = 0xB0
_INS: int = 0x06
Expand Down Expand Up @@ -130,6 +136,15 @@ def send_raw(self, cla: int, ins: int, p1: int, p2: int, payload: bytes):
header.append(len(payload))
return self._exchange(header + payload)

def send_raw_async(self, cla: int, ins: int, p1: int, p2: int, payload: bytes):
header = bytearray()
header.append(cla)
header.append(ins)
header.append(p1)
header.append(p2)
header.append(len(payload))
return self._exchange_async(header + payload)

def eip712_send_struct_def_struct_name(self, name: str):
return self._exchange_async(self._cmd_builder.eip712_send_struct_def_struct_name(name))

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

def sign(self,
bip32_path: str,
tx_params: dict):
tx_params: dict,
mode: SignMode = SignMode.BASIC):
tx = Web3().eth.account.create().sign_transaction(tx_params).rawTransaction
prefix = bytes()
suffix = []
Expand All @@ -223,7 +239,7 @@ def sign(self,
suffix = [int(tx_params["chainId"]), bytes(), bytes()]
decoded = rlp.decode(tx)[:-3] # remove already computed signature
tx = prefix + rlp.encode(decoded + suffix)
chunks = self._cmd_builder.sign(bip32_path, tx, suffix)
chunks = self._cmd_builder.sign(bip32_path, tx, mode)
for chunk in chunks[:-1]:
self._exchange(chunk)
return self._exchange_async(chunks[-1])
Expand Down Expand Up @@ -530,3 +546,15 @@ def provide_network_information(self,
assert response.status == StatusWord.OK
response = self._exchange(chunks[-1])
assert response.status == StatusWord.OK

def provide_enum_value(self, payload: bytes) -> RAPDU:
chunks = self._cmd_builder.provide_enum_value(payload)
for chunk in chunks[:-1]:
self._exchange(chunk)
return self._exchange(chunks[-1])

def provide_transaction_info(self, payload: bytes) -> RAPDU:
chunks = self._cmd_builder.provide_transaction_info(payload)
for chunk in chunks[:-1]:
self._exchange(chunk)
return self._exchange(chunks[-1])
28 changes: 25 additions & 3 deletions client/src/ledger_app_clients/ethereum/command_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class InsType(IntEnum):
SIGN = 0x04
PERSONAL_SIGN = 0x08
PROVIDE_ERC20_TOKEN_INFORMATION = 0x0a
EXTERNAL_PLUGIN_SETUP = 0x12
PROVIDE_NFT_INFORMATION = 0x14
SET_PLUGIN = 0x16
PERFORM_PRIVACY_OPERATION = 0x18
Expand All @@ -24,7 +25,8 @@ class InsType(IntEnum):
EIP712_SIGN = 0x0c
GET_CHALLENGE = 0x20
PROVIDE_TRUSTED_NAME = 0x22
EXTERNAL_PLUGIN_SETUP = 0x12
PROVIDE_ENUM_VALUE = 0x24
PROVIDE_TRANSACTION_INFO = 0x26
PROVIDE_NETWORK_INFORMATION = 0x30


Expand Down Expand Up @@ -261,15 +263,15 @@ def set_external_plugin(self, plugin_name: str, contract_address: bytes, selecto
0x00,
data)

def sign(self, bip32_path: str, rlp_data: bytes, vrs: list) -> list[bytes]:
def sign(self, bip32_path: str, rlp_data: bytes, p2: int) -> list[bytes]:
apdus = list()
payload = pack_derivation_path(bip32_path)
payload += rlp_data
p1 = P1Type.SIGN_FIRST_CHUNK
while len(payload) > 0:
apdus.append(self._serialize(InsType.SIGN,
p1,
0x00,
p2,
payload[:0xff]))
payload = payload[0xff:]
p1 = P1Type.SIGN_SUBSQT_CHUNK
Expand Down Expand Up @@ -427,3 +429,23 @@ def provide_network_information(self,
icon = icon[0xff:]
p1 = P1Type.FOLLOWING_CHUNK
return chunks

def common_tlv_serialize(self, tlv_payload: bytes, ins: InsType) -> list[bytes]:
chunks = list()
payload = struct.pack(">H", len(tlv_payload))
payload += tlv_payload
p1 = 1
while len(payload) > 0:
chunks.append(self._serialize(ins,
p1,
0x00,
payload[:0xff]))
payload = payload[0xff:]
p1 = 0
return chunks

def provide_enum_value(self, tlv_payload: bytes) -> list[bytes]:
return self.common_tlv_serialize(tlv_payload, InsType.PROVIDE_ENUM_VALUE)

def provide_transaction_info(self, tlv_payload: bytes) -> list[bytes]:
return self.common_tlv_serialize(tlv_payload, InsType.PROVIDE_TRANSACTION_INFO)
59 changes: 59 additions & 0 deletions client/src/ledger_app_clients/ethereum/enum_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from enum import IntEnum
from typing import Optional
from .tlv import format_tlv
from .keychain import sign_data, Key


class Tag(IntEnum):
VERSION = 0x00
CHAIN_ID = 0x01
CONTRACT_ADDR = 0x02
SELECTOR = 0x03
ID = 0x04
VALUE = 0x05
NAME = 0x06
SIGNATURE = 0xff


class EnumValue:
version: int
chain_id: int
contract_addr: bytes
selector: bytes
id: int
value: int
name: str
signature: Optional[bytes] = None

def __init__(self,
version: int,
chain_id: int,
contract_addr: bytes,
selector: bytes,
id: int,
value: int,
name: str,
signature: Optional[bytes] = None):
self.version = version
self.chain_id = chain_id
self.contract_addr = contract_addr
self.selector = selector
self.id = id
self.value = value
self.name = name
self.signature = signature

def serialize(self) -> bytes:
payload = bytearray()
payload += format_tlv(Tag.VERSION, self.version)
payload += format_tlv(Tag.CHAIN_ID, self.chain_id)
payload += format_tlv(Tag.CONTRACT_ADDR, self.contract_addr)
payload += format_tlv(Tag.SELECTOR, self.selector)
payload += format_tlv(Tag.ID, self.id)
payload += format_tlv(Tag.VALUE, self.value)
payload += format_tlv(Tag.NAME, self.name)
sig = self.signature
if sig is None:
sig = sign_data(Key.CAL, payload)
payload += format_tlv(Tag.SIGNATURE, sig)
return payload
Loading

0 comments on commit 3a2354b

Please sign in to comment.