Update the ragger app client to support "set external plugin" APDU and take into account PR review remarks

This commit is contained in:
tdejoigny-ledger
2023-08-04 13:43:03 +02:00
committed by Alexandre Paillier
parent eeb52344df
commit 5d1d16c2de
4 changed files with 66 additions and 30 deletions

View File

@@ -2,7 +2,7 @@ import rlp
from enum import IntEnum from enum import IntEnum
from ragger.backend import BackendInterface from ragger.backend import BackendInterface
from ragger.utils import RAPDU from ragger.utils import RAPDU
from typing import List, Optional, Union from typing import List, Optional
from .command_builder import CommandBuilder from .command_builder import CommandBuilder
from .eip712 import EIP712FieldType from .eip712 import EIP712FieldType
@@ -30,8 +30,7 @@ class StatusWord(IntEnum):
CONDITION_NOT_SATISFIED = 0x6985 CONDITION_NOT_SATISFIED = 0x6985
REF_DATA_NOT_FOUND = 0x6a88 REF_DATA_NOT_FOUND = 0x6a88
class DomainNameTag(IntEnum):
class DOMAIN_NAME_TAG(IntEnum):
STRUCTURE_TYPE = 0x01 STRUCTURE_TYPE = 0x01
STRUCTURE_VERSION = 0x02 STRUCTURE_VERSION = 0x02
CHALLENGE = 0x12 CHALLENGE = 0x12
@@ -52,7 +51,7 @@ class EthAppClient:
return self._client.exchange_async_raw(payload) return self._client.exchange_async_raw(payload)
def response(self) -> Optional[RAPDU]: def response(self) -> Optional[RAPDU]:
return self._client._last_async_response return self._client.last_async_response
def eip712_send_struct_def_struct_name(self, name: str): def eip712_send_struct_def_struct_name(self, name: str):
return self._send(self._cmd_builder.eip712_send_struct_def_struct_name(name)) return self._send(self._cmd_builder.eip712_send_struct_def_struct_name(name))
@@ -190,15 +189,15 @@ class EthAppClient:
chain_id)) chain_id))
def provide_domain_name(self, challenge: int, name: str, addr: bytes): def provide_domain_name(self, challenge: int, name: str, addr: bytes):
payload = format_tlv(DOMAIN_NAME_TAG.STRUCTURE_TYPE, 3) # TrustedDomainName payload = format_tlv(DomainNameTag.STRUCTURE_TYPE, 3) # TrustedDomainName
payload += format_tlv(DOMAIN_NAME_TAG.STRUCTURE_VERSION, 1) payload += format_tlv(DomainNameTag.STRUCTURE_VERSION, 1)
payload += format_tlv(DOMAIN_NAME_TAG.SIGNER_KEY_ID, 0) # test key payload += format_tlv(DomainNameTag.SIGNER_KEY_ID, 0) # test key
payload += format_tlv(DOMAIN_NAME_TAG.SIGNER_ALGO, 1) # secp256k1 payload += format_tlv(DomainNameTag.SIGNER_ALGO, 1) # secp256k1
payload += format_tlv(DOMAIN_NAME_TAG.CHALLENGE, challenge) payload += format_tlv(DomainNameTag.CHALLENGE, challenge)
payload += format_tlv(DOMAIN_NAME_TAG.COIN_TYPE, 0x3c) # ETH in slip-44 payload += format_tlv(DomainNameTag.COIN_TYPE, 0x3c) # ETH in slip-44
payload += format_tlv(DOMAIN_NAME_TAG.DOMAIN_NAME, name) payload += format_tlv(DomainNameTag.DOMAIN_NAME, name)
payload += format_tlv(DOMAIN_NAME_TAG.ADDRESS, addr) payload += format_tlv(DomainNameTag.ADDRESS, addr)
payload += format_tlv(DOMAIN_NAME_TAG.SIGNATURE, payload += format_tlv(DomainNameTag.SIGNATURE,
sign_data(Key.DOMAIN_NAME, payload)) sign_data(Key.DOMAIN_NAME, payload))
chunks = self._cmd_builder.provide_domain_name(payload) chunks = self._cmd_builder.provide_domain_name(payload)
@@ -271,3 +270,7 @@ class EthAppClient:
key_id, key_id,
algo_id, algo_id,
sig)) sig))
def external_plugin_setup(self, plugin_name: str, contract_address: bytes, method_selelector: bytes, sig: bytes):
return self._send(self._cmd_builder.external_plugin_setup(plugin_name, contract_address, method_selelector, sig))

View File

@@ -1,3 +1,6 @@
# documentation about APDU format is available here:
# https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc
import struct import struct
from enum import IntEnum from enum import IntEnum
from typing import Optional from typing import Optional
@@ -18,6 +21,7 @@ class InsType(IntEnum):
EIP712_SIGN = 0x0c EIP712_SIGN = 0x0c
GET_CHALLENGE = 0x20 GET_CHALLENGE = 0x20
PROVIDE_DOMAIN_NAME = 0x22 PROVIDE_DOMAIN_NAME = 0x22
EXTERNAL_PLUGIN_SETUP = 0x12
class P1Type(IntEnum): class P1Type(IntEnum):
@@ -178,6 +182,19 @@ class CommandBuilder:
P2Type.FILTERING_FIELD_NAME, P2Type.FILTERING_FIELD_NAME,
self._eip712_filtering_send_name(name, sig)) self._eip712_filtering_send_name(name, sig))
def external_plugin_setup(self, plugin_name: str, contract_address: bytes, method_selelector: bytes, sig: bytes) -> bytes:
data = bytearray()
data.append(len(plugin_name))
data += self._string_to_bytes(plugin_name)
data += contract_address
data += method_selelector
data += sig
return self._serialize(InsType.EXTERNAL_PLUGIN_SETUP,
P1Type.COMPLETE_SEND,
0x00,
data)
def sign(self, bip32_path: str, rlp_data: bytes) -> list[bytes]: def sign(self, bip32_path: str, rlp_data: bytes) -> list[bytes]:
apdus = list() apdus = list()
payload = pack_derivation_path(bip32_path) payload = pack_derivation_path(bip32_path)

View File

@@ -49,20 +49,36 @@ __attribute__((section(".boot"))) int main(int arg0) {
check_api_level(CX_COMPAT_APILEVEL); check_api_level(CX_COMPAT_APILEVEL);
// Check if plugin is called from the dashboard. BEGIN_TRY {
if (!arg0) { TRY {
// Called from dashboard, launch Ethereum app // Check if plugin is called from the dashboard.
call_app_ethereum(); if (!arg0) {
return 0; // Called from dashboard, launch Ethereum app
} else { call_app_ethereum();
// Not called from dashboard: called from the ethereum app!
// launch plugin main // Will not get reached.
plugin_main(arg0); __builtin_unreachable();
os_sched_exit(-1);
} else {
// Not called from dashboard: called from the ethereum app!
// launch plugin main
plugin_main(arg0);
}
// Call `os_lib_end`, go back to the ethereum app.
os_lib_end();
// Will not get reached.
__builtin_unreachable();
}
CATCH_OTHER(e) {
PRINTF("Exiting following exception: %d\n", e);
}
FINALLY {
os_lib_end();
}
} }
END_TRY;
// Call `os_lib_end`, go back to the ethereum app. }
os_lib_end();
// Will not get reached.
return 0;
}

View File

@@ -16,4 +16,4 @@
*****************************************************************************/ *****************************************************************************/
// applicative main for plugins // applicative main for plugins
void plugin_main(int arg0); void plugin_main(int arg0);