Add PKI class in client

This commit is contained in:
Charles-Edouard de la Vergne
2024-07-10 15:27:00 +02:00
parent a32e86ffd4
commit fbbd1f41a4
2 changed files with 131 additions and 0 deletions

View File

@@ -1,6 +1,8 @@
import rlp import rlp
from enum import IntEnum from enum import IntEnum
from ragger.backend import BackendInterface from ragger.backend import BackendInterface
from ragger.firmware import Firmware
from ragger.error import ExceptionRAPDU
from ragger.utils import RAPDU from ragger.utils import RAPDU
from typing import Optional from typing import Optional
@@ -22,6 +24,7 @@ class StatusWord(IntEnum):
CONDITION_NOT_SATISFIED = 0x6985 CONDITION_NOT_SATISFIED = 0x6985
REF_DATA_NOT_FOUND = 0x6a88 REF_DATA_NOT_FOUND = 0x6a88
EXCEPTION_OVERFLOW = 0x6807 EXCEPTION_OVERFLOW = 0x6807
NOT_IMPLEMENTED = 0x911c
class DomainNameTag(IntEnum): class DomainNameTag(IntEnum):
@@ -36,10 +39,52 @@ class DomainNameTag(IntEnum):
ADDRESS = 0x22 ADDRESS = 0x22
class PKIPubKeyUsage(IntEnum):
PUBKEY_USAGE_GENUINE_CHECK = 0x01
PUBKEY_USAGE_EXCHANGE_PAYLOAD = 0x02
PUBKEY_USAGE_NFT_METADATA = 0x03
PUBKEY_USAGE_TRUSTED_NAME = 0x04
PUBKEY_USAGE_BACKUP_PROVIDER = 0x05
PUBKEY_USAGE_RECOVER_ORCHESTRATOR = 0x06
PUBKEY_USAGE_PLUGIN_METADATA = 0x07
PUBKEY_USAGE_COIN_META = 0x08
PUBKEY_USAGE_SEED_ID_AUTH = 0x09
class PKIClient:
_CLA: int = 0xB0
_INS: int = 0x06
def __init__(self, client: BackendInterface) -> None:
self._client = client
def send_certificate(self, p1: PKIPubKeyUsage, payload: bytes) -> RAPDU:
try:
response = self.send_raw(p1, payload)
assert response.status == StatusWord.OK
except ExceptionRAPDU as err:
if err.status == StatusWord.NOT_IMPLEMENTED:
print("Ledger-PKI APDU not yet implemented. Legacy path will be used")
def send_raw(self, p1: PKIPubKeyUsage, payload: bytes) -> RAPDU:
header = bytearray()
header.append(self._CLA)
header.append(self._INS)
header.append(p1)
header.append(0x00)
header.append(len(payload))
return self._client.exchange_raw(header + payload)
class EthAppClient: class EthAppClient:
def __init__(self, client: BackendInterface): def __init__(self, client: BackendInterface):
self._client = client self._client = client
self._firmware = client.firmware
self._cmd_builder = CommandBuilder() self._cmd_builder = CommandBuilder()
self._pki_client: Optional[PKIClient] = None
if self._firmware != Firmware.NANOS:
# LedgerPKI not supported on Nanos
self._pki_client = PKIClient(self._client)
def _exchange_async(self, payload: bytes): def _exchange_async(self, payload: bytes):
return self._client.exchange_async_raw(payload) return self._client.exchange_async_raw(payload)
@@ -168,6 +213,23 @@ class EthAppClient:
pubkey)) pubkey))
def provide_domain_name(self, challenge: int, name: str, addr: bytes) -> RAPDU: def provide_domain_name(self, challenge: int, name: str, addr: bytes) -> RAPDU:
if self._pki_client is None:
print(f"Ledger-PKI Not supported on '{self._firmware.name}'")
else:
# pylint: disable=line-too-long
if self._firmware == Firmware.NANOSP:
cert_apdu = "01010102010210040102000011040000000212010013020002140101160400000000200b446f6d61696e5f4e616d6530020007310108320121332102b91fbec173e3ba4a714e014ebc827b6f899a9fa7f4ac769cde284317a00f4f653401013501031546304402201b5188f5af5cd4d40d2e5eee85609323ee129b789082d079644c89c0df9b6ce0022076c5d26bb5c8db8ab02771ecd577f63f68eaf1c90523173f161f9c12f6e978bd" # noqa: E501
elif self._firmware == Firmware.NANOX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F653401013501021546304402202CD052029B756890F0C56713409C58C24785FEFFD1A997E9C840A7BDB176B512022059A30E04E491CD27BD1DA1B5CB810CF8E4EAE67F6406F054FDFC371F7EB9F2C4" # noqa: E501
elif self._firmware == Firmware.STAX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154630440220741DB4E738749D4188436419B20B9AEF8F07581312A9B3C9BAA3F3E879690F6002204C4A3510569247777BC43DB830D129ACA8985B88552E2E234E14D8AA2863026B" # noqa: E501
elif self._firmware == Firmware.FLEX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350105154730450221008B6BBCE1716C0A06F110C77FE181F8395D1692441459A106411463F01A45D4A7022044AB69037E6FA9D1D1A409E00B202C2D4451D464C8E5D4962D509FE63153FE93" # noqa: E501
# pylint: enable=line-too-long
self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu))
payload = format_tlv(DomainNameTag.STRUCTURE_TYPE, 3) # TrustedDomainName payload = format_tlv(DomainNameTag.STRUCTURE_TYPE, 3) # TrustedDomainName
payload += format_tlv(DomainNameTag.STRUCTURE_VERSION, 1) payload += format_tlv(DomainNameTag.STRUCTURE_VERSION, 1)
payload += format_tlv(DomainNameTag.SIGNER_KEY_ID, 0) # test key payload += format_tlv(DomainNameTag.SIGNER_KEY_ID, 0) # test key
@@ -194,6 +256,23 @@ class EthAppClient:
key_id: int = 2, key_id: int = 2,
algo_id: int = 1, algo_id: int = 1,
sig: Optional[bytes] = None) -> RAPDU: sig: Optional[bytes] = None) -> RAPDU:
if self._pki_client is None:
print(f"Ledger-PKI Not supported on '{self._firmware.name}'")
else:
# pylint: disable=line-too-long
if self._firmware == Firmware.NANOSP:
cert_apdu = "01010102010210040102000011040000000212010013020002140101160400000000200A53657420506C7567696E30020003310107320121332103C055BC4ECF055E2D85085D35127A3DE6705C7F885055CD7071E87671BF191FE3340101350103154630440220401824348DA0E435C9BF16C3591665CFA1B7D8E729971BE884027E02BD3C35A102202289EE207B73D98E9E6110CC143EB929F03B99D54C63023C99561D3CE164D30F" # noqa: E501
elif self._firmware == Firmware.NANOX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200A53657420506C7567696E30020003310107320121332103C055BC4ECF055E2D85085D35127A3DE6705C7F885055CD7071E87671BF191FE334010135010215473045022100E657DE255F954779E14D281E2E739D89DEF2E943B7FD4B4AFE49CF4FF7E1D84F022057F29C9AEA8FAA25C8438FDEE85C6DABF270E5CEC1655F17F2D9A6ADCD3ADC0E" # noqa: E501
elif self._firmware == Firmware.STAX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200A53657420506C7567696E30020003310107320121332103C055BC4ECF055E2D85085D35127A3DE6705C7F885055CD7071E87671BF191FE334010135010415473045022100B8AF9667C190B60BF350D8F8CA66A4BCEA22BF47D757CB7F88F8D16C7794BCDC02205F7D6C8E9294F73744A82E1062B10FFEB809252682112E71A419EFC78227211B" # noqa: E501
elif self._firmware == Firmware.FLEX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200A53657420506C7567696E30020003310107320121332103C055BC4ECF055E2D85085D35127A3DE6705C7F885055CD7071E87671BF191FE334010135010515473045022100F5069D8BCEDCF7CC55273266E3871B09FFCACD084B5753347A809DDDA67E6235022003CE65364BFA96B6FE7A9D8C13EC87B8E727E8B7BF4A63176F5D61AB8F97807E" # noqa: E501
# pylint: enable=line-too-long
self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_PLUGIN_METADATA, bytes.fromhex(cert_apdu))
if sig is None: if sig is None:
# Temporarily get a command with an empty signature to extract the payload and # Temporarily get a command with an empty signature to extract the payload and
# compute the signature on it # compute the signature on it
@@ -227,6 +306,23 @@ class EthAppClient:
key_id: int = 1, key_id: int = 1,
algo_id: int = 1, algo_id: int = 1,
sig: Optional[bytes] = None) -> RAPDU: sig: Optional[bytes] = None) -> RAPDU:
if self._pki_client is None:
print(f"Ledger-PKI Not supported on '{self._firmware.name}'")
else:
# pylint: disable=line-too-long
if self._firmware == Firmware.NANOSP:
cert_apdu = "0101010201021004010200001104000000021201001302000214010116040000000020084e46545f496e666f300200043101033201213321023cfb5fb31905f4bd39d9d535a40c26aab51c5d7d3219b28ac942b980fb206cfb34010135010315473045022100d43e142a6639b27a79bc4f021854df48f1bc1e828ac47b105578cb527b69f525022078f6e6b3eb9bb787a0a29e85531ce3512c2d6481e761e840db0fb6b0898911a1" # noqa: E501
elif self._firmware == Firmware.NANOX:
cert_apdu = "0101010201021104000000021201001302000214010116040000000020084E46545F496E666F300200043101033201213321023CFB5FB31905F4BD39D9D535A40C26AAB51C5D7D3219B28AC942B980FB206CFB340101350102154730450221009BAE21BB8CBA6F95DDFF86AEEA991D63FA36A469A3071F61BDA8895F1A5F0AC3022061661F95D1513D3FDE81FFEA4B0C6D48ADCB27ED70915EE3ACD16A2A64CDE916" # noqa: E501
elif self._firmware == Firmware.STAX:
cert_apdu = "0101010201021104000000021201001302000214010116040000000020084E46545F496E666F300200043101033201213321023CFB5FB31905F4BD39D9D535A40C26AAB51C5D7D3219B28AC942B980FB206CFB3401013501041546304402201DEE04EC830FFDE5C98A708EC6865605FC14FF6105A54BE5230F2B954C673B940220581A0A5E42A7779140963703E43B3BEABE4C69284EDEF00E76BB5875E0810C9B" # noqa: E501
elif self._firmware == Firmware.FLEX:
cert_apdu = "0101010201021104000000021201001302000214010116040000000020084E46545F496E666F300200043101033201213321023CFB5FB31905F4BD39D9D535A40C26AAB51C5D7D3219B28AC942B980FB206CFB340101350105154730450221009ABCC7056D54C1B5DBB353178B13850C20521EE6884AA415AA61B329DB1D87F602204E308F273B8D18080184695438577F770524F717E5D08EE20ECBF1BC599F3538" # noqa: E501
# pylint: enable=line-too-long
self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_NFT_METADATA, bytes.fromhex(cert_apdu))
if sig is None: if sig is None:
# Temporarily get a command with an empty signature to extract the payload and # Temporarily get a command with an empty signature to extract the payload and
# compute the signature on it # compute the signature on it
@@ -278,6 +374,23 @@ class EthAppClient:
decimals: int, decimals: int,
chain_id: int, chain_id: int,
sig: Optional[bytes] = None) -> RAPDU: sig: Optional[bytes] = None) -> RAPDU:
if self._pki_client is None:
print(f"Ledger-PKI Not supported on '{self._firmware.name}'")
else:
# pylint: disable=line-too-long
if self._firmware == Firmware.NANOSP:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010310040102000015473045022100C15795C2AE41E6FAE6B1362EE1AE216428507D7C1D6939B928559CC7A1F6425C02206139CF2E133DD62F3E00F183E42109C9853AC62B6B70C5079B9A80DBB9D54AB5" # noqa: E501
elif self._firmware == Firmware.NANOX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010215473045022100E3B956F93FBFF0D41908483888F0F75D4714662A692F7A38DC6C41A13294F9370220471991BECB3CA4F43413CADC8FF738A8CC03568BFA832B4DCFE8C469080984E5" # noqa: E501
elif self._firmware == Firmware.STAX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501041546304402206731FCD3E2432C5CA162381392FD17AD3A41EEF852E1D706F21A656AB165263602204B89FAE8DBAF191E2D79FB00EBA80D613CB7EDF0BE960CB6F6B29D96E1437F5F" # noqa: E501
elif self._firmware == Firmware.FLEX:
cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010515473045022100B59EA8B958AA40578A6FBE9BBFB761020ACD5DBD8AA863C11DA17F42B2AFDE790220186316059EFA58811337D47C7F815F772EA42BBBCEA4AE123D1118C80588F5CB" # noqa: E501
# pylint: enable=line-too-long
self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu))
if sig is None: if sig is None:
# Temporarily get a command with an empty signature to extract the payload and # Temporarily get a command with an empty signature to extract the payload and
# compute the signature on it # compute the signature on it

View File

@@ -12,6 +12,8 @@ from client.client import EthAppClient, EIP712FieldType
from ragger.firmware import Firmware from ragger.firmware import Firmware
from client.client import PKIPubKeyUsage
# global variables # global variables
app_client: EthAppClient = None app_client: EthAppClient = None
filtering_paths: dict = {} filtering_paths: dict = {}
@@ -450,6 +452,22 @@ def process_data(aclient: EthAppClient,
pass pass
prepare_filtering(filters, message) prepare_filtering(filters, message)
if aclient._pki_client is None:
print(f"Ledger-PKI Not supported on '{aclient._firmware.name}'")
else:
# pylint: disable=line-too-long
if aclient._firmware == Firmware.NANOSP:
cert_apdu = "0101010201021004010200001104000000021201001302000214010116040000000020104549503731325f46696c746572696e67300200053101083201213321024cca8fad496aa5040a00a7eb2f5cc3b85376d88ba147a7d7054a99c64056188734010135010315473045022100ef197e5b1cabb3de5dfc62f965db8536b0463d272c6fea38ebc73605715b1df9022017bef619d52a9728b37a9b5a33f0143bcdcc714694eed07c326796ffbb7c2958" # noqa: E501
elif aclient._firmware == Firmware.NANOX:
cert_apdu = "0101010201021104000000021201001302000214010116040000000020104549503731325F46696C746572696E67300200053101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010215473045022100E07E129B0DC2A571D5205C3DB43BF4BB3463A2E9D2A4EEDBEC8FD3518CC5A95902205F80306EEF785C4D45BDCA1F25394A1341571BD1921C2740392DD22EB1ACDD8B" # noqa: E501
elif aclient._firmware == Firmware.STAX:
cert_apdu = "0101010201021104000000021201001302000214010116040000000020104549503731325F46696C746572696E67300200053101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501041546304402204EA7B30F0EEFEF25FAB3ADDA6609E25296C41DD1C5969A92FAE6B600AAC2902E02206212054E123F5F965F787AE7EE565E243F21B11725626D3FF058522D6BDCD995" # noqa: E501
elif aclient._firmware == Firmware.FLEX:
cert_apdu = "0101010201021104000000021201001302000214010116040000000020104549503731325F46696C746572696E67300200053101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501051546304402205FB5E970065A95C57F00FFA3964946251815527613724ED6745C37E303934BE702203CC9F4124B42806F0A7CA765CFAB5AADEB280C35AB8F809FC49ADC97D9B9CE15" # noqa: E501
# pylint: enable=line-too-long
aclient._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu))
# send domain implementation # send domain implementation
with app_client.eip712_send_struct_impl_root_struct(domain_typename): with app_client.eip712_send_struct_impl_root_struct(domain_typename):
enable_autonext() enable_autonext()