Compare commits

...

12 Commits

Author SHA1 Message Date
defiQUG
e941a5d06d Added Chain: Defi Oracle Meta - Chain ID 138
Some checks failed
Build and run functional tests using ragger through reusable workflow / Build application using the reusable workflow (push) Has been cancelled
Build and run functional tests using ragger through reusable workflow / Build Clone app using the reusable workflow (push) Has been cancelled
Check SDK submodule version / Check Ethereum plugin SDK submodule is up-to-date (push) Has been cancelled
CodeQL / Analyse (cpp, $FLEX_SDK) (push) Has been cancelled
CodeQL / Analyse (cpp, $NANOSP_SDK) (push) Has been cancelled
CodeQL / Analyse (cpp, $NANOS_SDK) (push) Has been cancelled
CodeQL / Analyse (cpp, $NANOX_SDK) (push) Has been cancelled
CodeQL / Analyse (cpp, $STAX_SDK) (push) Has been cancelled
Misspellings CI / Check misspellings (push) Has been cancelled
Ensure compliance with Ledger guidelines / Call Ledger guidelines_enforcer (push) Has been cancelled
Code style check / Check linting using the reusable workflow (push) Has been cancelled
Code style check / Check yaml files (push) Has been cancelled
Swap functional tests / job_functional_tests (push) Has been cancelled
Build and run functional tests using ragger through reusable workflow / Run ragger tests using the reusable workflow (push) Has been cancelled
Build and run functional tests using ragger through reusable workflow / Run ragger Clone tests using the reusable workflow (push) Has been cancelled
- Added new glyph and icon for Chain 138
- Created makefile configuration for Defi Oracle
- Updated network handling in src/network.c
- Modified address retrieval test
2024-08-08 00:04:03 -07:00
Charles-Edouard de la Vergne
19646219e5 Merge pull request #592 from LedgerHQ/cev/add-ledger-pki
Add Ledger PKI
2024-08-07 16:45:25 +02:00
Charles-Edouard de la Vergne
338f7cef45 Adapt test to provide certificate APDU 2024-08-07 14:41:42 +02:00
Charles-Edouard de la Vergne
1a555d0996 Fix client 'settings_toggle' offset computation 2024-08-07 14:41:42 +02:00
Charles-Edouard de la Vergne
fbbd1f41a4 Add PKI class in client 2024-08-07 14:41:41 +02:00
Charles-Edouard de la Vergne
a32e86ffd4 Return a dedicated error if Ledger-PKI APDU received but feature not enabled 2024-08-07 14:41:41 +02:00
Charles-Edouard de la Vergne
2008307c0c Implement Ledger-PKI
- Update src code to adapt to new API 'os_pki_verify'
- Support both Ledger-PKI and legacy method
2024-08-07 14:41:40 +02:00
François Beutin
c480a311ed Merge pull request #622 from LedgerHQ/fbe/restore_compatibility_in_vscode
Restore compatibility in vscode
2024-08-01 17:42:24 +02:00
Francois Beutin
53d2196a19 Revert use case name change in manifest to restore compatibility 2024-08-01 17:37:08 +02:00
Francois Beutin
c310d00a6f Add flag for sdk compilation 2024-08-01 17:37:08 +02:00
Charles-Edouard de la Vergne
1ac75092da Fix deprecated 'encodeABI' 2024-08-01 14:33:09 +02:00
Charles-Edouard de la Vergne
f4a29413a1 Cleaup useless flags 2024-07-30 09:32:34 +02:00
26 changed files with 467 additions and 441 deletions

View File

@@ -80,6 +80,9 @@ ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_STAX TARGET_FLEX))
DEFINES += ICONGLYPH_SMALL=C_chain_$(CHAIN_ID) DEFINES += ICONGLYPH_SMALL=C_chain_$(CHAIN_ID)
endif endif
# Don't define plugin function in the plugin SDK
DEFINES += IS_NOT_A_PLUGIN
# Application allowed derivation curves. # Application allowed derivation curves.
# Possibles curves are: secp256k1, secp256r1, ed25519 and bls12381g1 # Possibles curves are: secp256k1, secp256r1, ed25519 and bls12381g1

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()

View File

@@ -25,32 +25,35 @@ def get_device_settings(firmware: Firmware) -> list[SettingID]:
] ]
def get_setting_per_page(firmware: Firmware) -> int: def get_setting_position(firmware: Firmware, setting_idx: int, per_page: int) -> tuple[int, int]:
if firmware == Firmware.STAX:
return 3
return 2
def get_setting_position(firmware: Firmware, setting: Union[NavInsID, SettingID]) -> tuple[int, int]:
settings_per_page = get_setting_per_page(firmware)
if firmware == Firmware.STAX: if firmware == Firmware.STAX:
screen_height = 672 # px screen_height = 672 # px
header_height = 88 # px header_height = 88 # px
footer_height = 92 # px footer_height = 92 # px
option_offset = 350 # px x_offset = 350 # px
else: else:
screen_height = 600 # px screen_height = 600 # px
header_height = 92 # px header_height = 92 # px
footer_height = 97 # px footer_height = 97 # px
option_offset = 420 # px x_offset = 420 # px
usable_height = screen_height - (header_height + footer_height) index_in_page = setting_idx % per_page
setting_height = usable_height // settings_per_page if index_in_page == 0:
index_in_page = get_device_settings(firmware).index(SettingID(setting)) % settings_per_page y_offset = header_height + 10
return option_offset, header_height + (setting_height * index_in_page) + (setting_height // 2) elif per_page == 3:
if setting_idx == 1:
# 2nd setting over 3: middle of the screen
y_offset = screen_height // 2
else:
# Last setting
y_offset = screen_height - footer_height - 10
else:
# 2 per page, requesting the 2nd one; middle of screen is ok
y_offset = screen_height // 2
return x_offset, y_offset
def settings_toggle(firmware: Firmware, nav: Navigator, to_toggle: list[SettingID]): def settings_toggle(firmware: Firmware, nav: Navigator, to_toggle: list[SettingID]):
moves: list[Union[NavIns, NavInsID]] = list() moves: list[Union[NavIns, NavInsID]] = []
settings = get_device_settings(firmware) settings = get_device_settings(firmware)
# Assume the app is on the home page # Assume the app is on the home page
if firmware.is_nano: if firmware.is_nano:
@@ -63,12 +66,12 @@ def settings_toggle(firmware: Firmware, nav: Navigator, to_toggle: list[SettingI
moves += [NavInsID.BOTH_CLICK] # Back moves += [NavInsID.BOTH_CLICK] # Back
else: else:
moves += [NavInsID.USE_CASE_HOME_SETTINGS] moves += [NavInsID.USE_CASE_HOME_SETTINGS]
settings_per_page = get_setting_per_page(firmware) settings_per_page = 3 if firmware == Firmware.STAX else 2
for setting in settings: for setting in settings:
setting_idx = settings.index(setting) setting_idx = settings.index(setting)
if (setting_idx > 0) and (setting_idx % settings_per_page) == 0: if (setting_idx > 0) and (setting_idx % settings_per_page) == 0:
moves += [NavInsID.USE_CASE_SETTINGS_NEXT] moves += [NavInsID.USE_CASE_SETTINGS_NEXT]
if setting in to_toggle: if setting in to_toggle:
moves += [NavIns(NavInsID.TOUCH, get_setting_position(firmware, setting))] moves += [NavIns(NavInsID.TOUCH, get_setting_position(firmware, setting_idx, settings_per_page))]
moves += [NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT] moves += [NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT]
nav.navigate(moves, screen_change_before_first_instruction=False) nav.navigate(moves, screen_change_before_first_instruction=False)

BIN
glyphs/chain_138_64px.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -4,8 +4,8 @@ sdk = "C"
devices = ["nanos", "nanox", "nanos+", "stax", "flex"] devices = ["nanos", "nanox", "nanos+", "stax", "flex"]
[use_cases] # Coherent build options that make sense for your application [use_cases] # Coherent build options that make sense for your application
test_keys = "CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1" use_test_keys = "CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
dbg_test_keys = "DEBUG=1 CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1" dbg_use_test_keys = "DEBUG=1 CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
cal_bypass = "BYPASS_SIGNATURES=1" cal_bypass = "BYPASS_SIGNATURES=1"
dbg_cal_bypass = "DEBUG=1 BYPASS_SIGNATURES=1" dbg_cal_bypass = "DEBUG=1 BYPASS_SIGNATURES=1"

View File

@@ -0,0 +1,4 @@
PATH_APP_LOAD_PARAMS += "44'/60'"
TICKER = "ETH"
CHAIN_ID = 138
APPNAME = "Defi Oracle Meta"

View File

@@ -1,61 +0,0 @@
/*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#ifdef HAVE_TOKENS_EXTRA_LIST
#include "extra_tokens.h"
const tokenDefinition_t TOKENS_EXTRA[NUM_TOKENS_EXTRA] = {
// Ropsten DeversiFi tokens
{{0x4c, 0x5f, 0x66, 0x59, 0x61, 0x97, 0xa8, 0x6f, 0xb3, 0x0a,
0x24, 0x35, 0xe2, 0xef, 0x4d, 0xdc, 0xb3, 0x93, 0x42, 0xc9},
"tUSDT",
6},
{{0x1c, 0x0f, 0x17, 0x43, 0x67, 0x40, 0xbf, 0xb9, 0x2c, 0x10,
0x70, 0xee, 0x86, 0x32, 0x2d, 0xe8, 0x90, 0x83, 0x7c, 0x6a},
"tUSDT",
6},
{{0xcd, 0x07, 0x7a, 0xbe, 0xdd, 0x83, 0x1a, 0x34, 0x43, 0xff,
0xbe, 0x24, 0xfb, 0x76, 0x66, 0x1b, 0xbb, 0x17, 0xeb, 0x69},
"tZRX",
18},
{{0x40, 0xd8, 0x97, 0x85, 0x00, 0xbf, 0x68, 0x32, 0x4a, 0x51,
0x53, 0x3c, 0xd6, 0xa2, 0x1e, 0x3e, 0x59, 0xbe, 0x32, 0x4a},
"tBTC",
18},
// Goerli DeversiFi tokens
{{0xd9, 0x97, 0xa8, 0x63, 0x46, 0xe7, 0x65, 0x18, 0xe6, 0x92,
0x25, 0x56, 0xf3, 0x4d, 0x76, 0x61, 0x30, 0xc0, 0xbb, 0xfd},
"tUSDT",
6},
{{0xc1, 0xd5, 0x79, 0xeb, 0xff, 0x7c, 0x0f, 0x6c, 0xfd, 0x9a,
0xd5, 0xfb, 0x26, 0x7f, 0xec, 0x73, 0xbe, 0x70, 0xc8, 0xf7},
"tBTC",
18},
{{0xa8, 0xf3, 0x14, 0x4f, 0xea, 0x2c, 0x37, 0x5a, 0xd0, 0x58,
0xec, 0x12, 0x09, 0x9a, 0x5a, 0x21, 0xa2, 0x6f, 0xe9, 0x96},
"tDVF",
18},
{{0x4c, 0xda, 0xbe, 0xc1, 0x2a, 0x39, 0x7f, 0xb6, 0xef, 0xaf,
0x46, 0x13, 0xd5, 0xdf, 0xd7, 0x9b, 0x30, 0x9a, 0xe9, 0xfa},
"tXDVF",
18},
};
#endif

View File

@@ -1,28 +0,0 @@
/*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#pragma once
#include "asset_info.h"
#ifdef HAVE_TOKENS_EXTRA_LIST
#define NUM_TOKENS_EXTRA 8
extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
#endif

76
src/ledger_pki.c Normal file
View File

@@ -0,0 +1,76 @@
#include "apdu_constants.h"
#include "public_keys.h"
#ifdef HAVE_LEDGER_PKI
#include "os_pki.h"
#endif
#define KEY_USAGE_STR(x) \
(x == CERTIFICATE_PUBLIC_KEY_USAGE_GENUINE_CHECK ? "GENUINE_CHECK" \
: x == CERTIFICATE_PUBLIC_KEY_USAGE_EXCHANGE_PAYLOAD ? "EXCHANGE_PAYLOAD" \
: x == CERTIFICATE_PUBLIC_KEY_USAGE_NFT_METADATA ? "NFT_METADATA" \
: x == CERTIFICATE_PUBLIC_KEY_USAGE_TRUSTED_NAME ? "TRUSTED_NAME" \
: x == CERTIFICATE_PUBLIC_KEY_USAGE_BACKUP_PROVIDER ? "BACKUP_PROVIDER" \
: x == CERTIFICATE_PUBLIC_KEY_USAGE_RECOVER_ORCHESTRATOR ? "RECOVER_ORCHESTRATOR" \
: x == CERTIFICATE_PUBLIC_KEY_USAGE_PLUGIN_METADATA ? "PLUGIN_METADATA" \
: x == CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META ? "COIN_META" \
: x == CERTIFICATE_PUBLIC_KEY_USAGE_SEED_ID_AUTH ? "SEED_ID_AUTH" \
: "Unknown")
int check_signature_with_pubkey(const char *tag,
uint8_t *buffer,
const uint8_t bufLen,
const uint8_t *PubKey,
const uint8_t keyLen,
#ifdef HAVE_LEDGER_PKI
const uint8_t keyUsageExp,
#endif
uint8_t *signature,
const uint8_t sigLen) {
UNUSED(tag);
cx_ecfp_public_key_t verif_key = {0};
cx_err_t error = CX_INTERNAL_ERROR;
#ifdef HAVE_LEDGER_PKI
uint8_t key_usage = 0;
size_t trusted_name_len = 0;
uint8_t trusted_name[CERTIFICATE_TRUSTED_NAME_MAXLEN] = {0};
cx_ecfp_384_public_key_t public_key = {0};
#endif
PRINTF(
"[%s] "
"=======================================================================================\n",
tag);
#ifdef HAVE_LEDGER_PKI
error = os_pki_get_info(&key_usage, trusted_name, &trusted_name_len, &public_key);
if ((error == 0) && (key_usage == keyUsageExp)) {
PRINTF("[%s] Certificate '%s' loaded for usage 0x%x (%s)\n",
tag,
trusted_name,
key_usage,
KEY_USAGE_STR(key_usage));
// Checking the signature with PKI
if (!os_pki_verify(buffer, bufLen, signature, sigLen)) {
PRINTF("%s: Invalid signature\n", tag);
#ifndef HAVE_BYPASS_SIGNATURES
error = APDU_RESPONSE_INVALID_DATA;
goto end;
#endif
}
} else
#endif
{
PRINTF("[%s] ********** No certificate loaded. Using legacy path **********\n", tag);
CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, PubKey, keyLen, &verif_key));
if (!cx_ecdsa_verify_no_throw(&verif_key, buffer, bufLen, signature, sigLen)) {
PRINTF("%s: Invalid signature\n", tag);
#ifndef HAVE_BYPASS_SIGNATURES
error = APDU_RESPONSE_INVALID_DATA;
goto end;
#endif
}
}
error = CX_OK;
end:
return error;
}

View File

@@ -150,6 +150,15 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
BEGIN_TRY { BEGIN_TRY {
TRY { TRY {
#ifndef HAVE_LEDGER_PKI
if ((G_io_apdu_buffer[OFFSET_CLA] == 0xB0 && (G_io_apdu_buffer[OFFSET_INS] == 0x06))) {
// Ledger-PKI APDU not yet caught by the running OS.
// Command code not supported
PRINTF("Ledger-PKI not yet supported!\n");
THROW(0x911C);
}
#endif // HAVE_LEDGER_PKI
if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { if (G_io_apdu_buffer[OFFSET_CLA] != CLA) {
THROW(0x6E00); THROW(0x6E00);
} }

View File

@@ -39,6 +39,7 @@ static const network_info_t NETWORK_MAPPING[] = {
{.chain_id = 100, .name = "Gnosis", .ticker = "xDAI"}, {.chain_id = 100, .name = "Gnosis", .ticker = "xDAI"},
{.chain_id = 106, .name = "Velas EVM", .ticker = "VLX"}, {.chain_id = 106, .name = "Velas EVM", .ticker = "VLX"},
{.chain_id = 137, .name = "Polygon", .ticker = "MATIC"}, {.chain_id = 137, .name = "Polygon", .ticker = "MATIC"},
{.chain_id = 138, .name = "Defi Oracle Meta", .ticker = "ETH"},
{.chain_id = 196, .name = "OKBChain Mainnet", .ticker = "OKB"}, {.chain_id = 196, .name = "OKBChain Mainnet", .ticker = "OKB"},
{.chain_id = 199, .name = "BTTC", .ticker = "BTT"}, {.chain_id = 199, .name = "BTTC", .ticker = "BTT"},
{.chain_id = 246, .name = "EnergyWebChain", .ticker = "EWT"}, {.chain_id = 246, .name = "EnergyWebChain", .ticker = "EWT"},

View File

@@ -16,6 +16,7 @@
********************************************************************************/ ********************************************************************************/
#pragma once #pragma once
#include <stdint.h>
static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = { static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
#if defined(HAVE_CAL_TEST_KEY) #if defined(HAVE_CAL_TEST_KEY)
@@ -101,3 +102,14 @@ static const uint8_t LEDGER_NFT_SELECTOR_PUBLIC_KEY[] = {
0x92, 0xc7, 0xc6, 0x48, 0x0d, 0x39, 0xce, 0xbb, 0xa3 0x92, 0xc7, 0xc6, 0x48, 0x0d, 0x39, 0xce, 0xbb, 0xa3
#endif #endif
}; };
extern int check_signature_with_pubkey(const char *tag,
uint8_t *buffer,
const uint8_t bufLen,
const uint8_t *PubKey,
const uint8_t keyLen,
#ifdef HAVE_LEDGER_PKI
const uint8_t keyUsageExp,
#endif
uint8_t *signature,
const uint8_t sigLen);

View File

@@ -12,6 +12,9 @@
#include "hash_bytes.h" #include "hash_bytes.h"
#include "network.h" #include "network.h"
#include "public_keys.h" #include "public_keys.h"
#ifdef HAVE_LEDGER_PKI
#include "os_pki.h"
#endif
#define P1_FIRST_CHUNK 0x01 #define P1_FIRST_CHUNK 0x01
#define P1_FOLLOWING_CHUNK 0x00 #define P1_FOLLOWING_CHUNK 0x00
@@ -364,39 +367,36 @@ static bool handle_address(const s_tlv_data *data,
*/ */
static bool verify_signature(const s_sig_ctx *sig_ctx) { static bool verify_signature(const s_sig_ctx *sig_ctx) {
uint8_t hash[INT256_LENGTH]; uint8_t hash[INT256_LENGTH];
cx_ecfp_public_key_t verif_key;
cx_err_t error = CX_INTERNAL_ERROR; cx_err_t error = CX_INTERNAL_ERROR;
CX_CHECK(
cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH));
switch (sig_ctx->key_id) {
#ifdef HAVE_DOMAIN_NAME_TEST_KEY #ifdef HAVE_DOMAIN_NAME_TEST_KEY
case KEY_ID_TEST: e_key_id valid_key_id = KEY_ID_TEST;
#else #else
case KEY_ID_PROD: e_key_id valid_key_id = KEY_ID_PROD;
#endif #endif
CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, bool ret_code = false;
DOMAIN_NAME_PUB_KEY,
sizeof(DOMAIN_NAME_PUB_KEY), if (sig_ctx->key_id != valid_key_id) {
&verif_key));
break;
default:
PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id); PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id);
return false; return false;
} }
if (!cx_ecdsa_verify_no_throw(&verif_key,
CX_CHECK(
cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH));
CX_CHECK(check_signature_with_pubkey("Domain Name",
hash, hash,
sizeof(hash), sizeof(hash),
sig_ctx->input_sig, DOMAIN_NAME_PUB_KEY,
sig_ctx->input_sig_size)) { sizeof(DOMAIN_NAME_PUB_KEY),
PRINTF("Domain name signature verification failed!\n"); #ifdef HAVE_LEDGER_PKI
#ifndef HAVE_BYPASS_SIGNATURES CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META,
return false;
#endif #endif
} (uint8_t *) (sig_ctx->input_sig),
return true; sig_ctx->input_sig_size));
ret_code = true;
end: end:
return false; return ret_code;
} }
/** /**

View File

@@ -3,101 +3,11 @@
#include "public_keys.h" #include "public_keys.h"
#include "common_ui.h" #include "common_ui.h"
#include "os_io_seproxyhal.h" #include "os_io_seproxyhal.h"
#include "extra_tokens.h"
#include "network.h" #include "network.h"
#include "manage_asset_info.h" #include "manage_asset_info.h"
#ifdef HAVE_LEDGER_PKI
#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR #include "os_pki.h"
void handleProvideErc20TokenInformation(uint8_t p1,
uint8_t p2,
const uint8_t *workBuffer,
uint8_t dataLength,
unsigned int *flags,
unsigned int *tx) {
UNUSED(p1);
UNUSED(p2);
UNUSED(flags);
uint32_t offset = 0;
uint8_t tickerLength, contractNameLength;
uint32_t chainId;
uint8_t hash[INT256_LENGTH];
cx_sha256_t sha256;
cx_ecfp_public_key_t tokenKey;
cx_sha256_init(&sha256);
tokenDefinition_t *token = &get_current_asset_info()->token;
if (dataLength < 1) {
THROW(0x6A80);
}
tickerLength = workBuffer[offset++];
dataLength--;
if ((tickerLength + 2) >= sizeof(token->ticker)) { // +2 because ' \0' is appended to ticker
THROW(0x6A80);
}
if (dataLength < tickerLength + 1) {
THROW(0x6A80);
}
cx_hash((cx_hash_t *) &sha256, 0, workBuffer + offset, tickerLength, NULL, 0);
memmove(token->ticker, workBuffer + offset, tickerLength);
token->ticker[tickerLength] = '\0';
offset += tickerLength;
dataLength -= tickerLength;
contractNameLength = workBuffer[offset++];
dataLength--;
if (dataLength < contractNameLength + 20 + 4 + 4) {
THROW(0x6A80);
}
cx_hash((cx_hash_t *) &sha256,
CX_LAST,
workBuffer + offset,
contractNameLength + 20 + 4 + 4,
hash,
32);
memmove(token->contractName,
workBuffer + offset,
MIN(contractNameLength, sizeof(token->contractName) - 1));
token->contractName[MIN(contractNameLength, sizeof(token->contractName) - 1)] = '\0';
offset += contractNameLength;
dataLength -= contractNameLength;
memmove(token->address, workBuffer + offset, 20);
offset += 20;
dataLength -= 20;
token->decimals = U4BE(workBuffer, offset);
offset += 4;
dataLength -= 4;
chainId = U4BE(workBuffer, offset);
if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
PRINTF("ChainId token mismatch\n");
THROW(0x6A80);
}
offset += 4;
dataLength -= 4;
cx_ecfp_init_public_key(CX_CURVE_256K1,
LEDGER_SIGNATURE_PUBLIC_KEY,
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
&tokenKey);
if (!cx_ecdsa_verify(&tokenKey,
CX_LAST,
CX_SHA256,
hash,
32,
workBuffer + offset,
dataLength)) {
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid token signature\n");
THROW(0x6A80);
#endif #endif
}
validate_current_asset_info();
THROW(0x9000);
}
#else
void handleProvideErc20TokenInformation(uint8_t p1, void handleProvideErc20TokenInformation(uint8_t p1,
uint8_t p2, uint8_t p2,
@@ -113,22 +23,21 @@ void handleProvideErc20TokenInformation(uint8_t p1,
uint8_t tickerLength; uint8_t tickerLength;
uint64_t chain_id; uint64_t chain_id;
uint8_t hash[INT256_LENGTH]; uint8_t hash[INT256_LENGTH];
cx_ecfp_public_key_t tokenKey;
tokenDefinition_t *token = &get_current_asset_info()->token; tokenDefinition_t *token = &get_current_asset_info()->token;
cx_err_t error = CX_INTERNAL_ERROR;
PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex); PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex);
if (dataLength < 1) { if (dataLength < 1) {
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
tickerLength = workBuffer[offset++]; tickerLength = workBuffer[offset++];
dataLength--; dataLength--;
if ((tickerLength + 1) > sizeof(token->ticker)) { if ((tickerLength + 1) > sizeof(token->ticker)) {
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
if (dataLength < tickerLength + 20 + 4 + 4) { if (dataLength < tickerLength + 20 + 4 + 4) {
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32); cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32);
memmove(token->ticker, workBuffer + offset, tickerLength); memmove(token->ticker, workBuffer + offset, tickerLength);
@@ -146,43 +55,29 @@ void handleProvideErc20TokenInformation(uint8_t p1,
chain_id = U4BE(workBuffer, offset); chain_id = U4BE(workBuffer, offset);
if (!app_compatible_with_chain_id(&chain_id)) { if (!app_compatible_with_chain_id(&chain_id)) {
UNSUPPORTED_CHAIN_ID_MSG(chain_id); UNSUPPORTED_CHAIN_ID_MSG(chain_id);
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
offset += 4; offset += 4;
dataLength -= 4; dataLength -= 4;
#ifdef HAVE_TOKENS_EXTRA_LIST error = check_signature_with_pubkey("ERC20 Token Info",
tokenDefinition_t *currentToken = NULL; hash,
uint32_t index; sizeof(hash),
for (index = 0; index < NUM_TOKENS_EXTRA; index++) {
currentToken = (tokenDefinition_t *) PIC(&TOKENS_EXTRA[index]);
if (memcmp(currentToken->address, token->address, 20) == 0) {
strcpy((char *) token->ticker, (char *) currentToken->ticker);
token->decimals = currentToken->decimals;
break;
}
}
if (index < NUM_TOKENS_EXTRA) {
PRINTF("Descriptor whitelisted\n");
} else
#endif
{
CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1,
LEDGER_SIGNATURE_PUBLIC_KEY, LEDGER_SIGNATURE_PUBLIC_KEY,
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
&tokenKey)); #ifdef HAVE_LEDGER_PKI
if (!cx_ecdsa_verify_no_throw(&tokenKey, hash, 32, workBuffer + offset, dataLength)) { CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META,
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid token signature\n");
THROW(0x6A80);
#endif #endif
(uint8_t *) (workBuffer + offset),
dataLength);
#ifndef HAVE_BYPASS_SIGNATURES
if (error != CX_OK) {
THROW(APDU_RESPONSE_INVALID_DATA);
} }
} #endif
G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex; G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex;
validate_current_asset_info(); validate_current_asset_info();
U2BE_ENCODE(G_io_apdu_buffer, 1, APDU_RESPONSE_OK); U2BE_ENCODE(G_io_apdu_buffer, 1, APDU_RESPONSE_OK);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 3); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 3);
} }
#endif

View File

@@ -9,6 +9,9 @@
#include "network.h" #include "network.h"
#include "public_keys.h" #include "public_keys.h"
#include "manage_asset_info.h" #include "manage_asset_info.h"
#ifdef HAVE_LEDGER_PKI
#include "os_pki.h"
#endif
#define TYPE_SIZE 1 #define TYPE_SIZE 1
#define VERSION_SIZE 1 #define VERSION_SIZE 1
@@ -50,19 +53,29 @@ void handleProvideNFTInformation(uint8_t p1,
UNUSED(tx); UNUSED(tx);
UNUSED(flags); UNUSED(flags);
uint8_t hash[INT256_LENGTH]; uint8_t hash[INT256_LENGTH];
cx_ecfp_public_key_t nftKey; nftInfo_t *nft = NULL;
size_t offset = 0;
size_t payloadSize = 0;
uint8_t collectionNameLength = 0;
uint64_t chain_id = 0;
uint8_t signatureLen = 0;
cx_err_t error = CX_INTERNAL_ERROR;
#ifdef HAVE_NFT_STAGING_KEY
uint8_t valid_keyId = STAGING_NFT_METADATA_KEY;
#else
uint8_t valid_keyId = PROD_NFT_METADATA_KEY;
#endif
PRINTF("In handle provide NFTInformation\n"); PRINTF("In handle provide NFTInformation\n");
if ((pluginType != ERC721) && (pluginType != ERC1155)) { if ((pluginType != ERC721) && (pluginType != ERC1155)) {
PRINTF("NFT metadata provided without proper plugin loaded!\n"); PRINTF("NFT metadata provided without proper plugin loaded!\n");
THROW(0x6985); THROW(0x6985);
} }
nftInfo_t *nft = &get_current_asset_info()->nft; nft = &get_current_asset_info()->nft;
PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex); PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex);
size_t offset = 0;
if (dataLength <= HEADER_SIZE) { if (dataLength <= HEADER_SIZE) {
PRINTF("Data too small for headers: expected at least %d, got %d\n", PRINTF("Data too small for headers: expected at least %d, got %d\n",
HEADER_SIZE, HEADER_SIZE,
@@ -70,33 +83,23 @@ void handleProvideNFTInformation(uint8_t p1,
THROW(APDU_RESPONSE_INVALID_DATA); THROW(APDU_RESPONSE_INVALID_DATA);
} }
uint8_t type = workBuffer[offset]; if (workBuffer[offset] != TYPE_1) {
switch (type) { PRINTF("Unsupported type %d\n", workBuffer[offset]);
case TYPE_1:
break;
default:
PRINTF("Unsupported type %d\n", type);
THROW(APDU_RESPONSE_INVALID_DATA); THROW(APDU_RESPONSE_INVALID_DATA);
break;
} }
offset += TYPE_SIZE; offset += TYPE_SIZE;
uint8_t version = workBuffer[offset]; if (workBuffer[offset] != VERSION_1) {
switch (version) { PRINTF("Unsupported version %d\n", workBuffer[offset]);
case VERSION_1:
break;
default:
PRINTF("Unsupported version %d\n", version);
THROW(APDU_RESPONSE_INVALID_DATA); THROW(APDU_RESPONSE_INVALID_DATA);
break;
} }
offset += VERSION_SIZE; offset += VERSION_SIZE;
uint8_t collectionNameLength = workBuffer[offset]; collectionNameLength = workBuffer[offset];
offset += NAME_LENGTH_SIZE; offset += NAME_LENGTH_SIZE;
// Size of the payload (everything except the signature) // Size of the payload (everything except the signature)
size_t payloadSize = HEADER_SIZE + collectionNameLength + ADDRESS_LENGTH + CHAIN_ID_SIZE + payloadSize = HEADER_SIZE + collectionNameLength + ADDRESS_LENGTH + CHAIN_ID_SIZE +
KEY_ID_SIZE + ALGORITHM_ID_SIZE; KEY_ID_SIZE + ALGORITHM_ID_SIZE;
if (dataLength < payloadSize) { if (dataLength < payloadSize) {
PRINTF("Data too small for payload: expected at least %d, got %d\n", PRINTF("Data too small for payload: expected at least %d, got %d\n",
@@ -124,7 +127,7 @@ void handleProvideNFTInformation(uint8_t p1,
PRINTF("Address: %.*H\n", ADDRESS_LENGTH, workBuffer + offset); PRINTF("Address: %.*H\n", ADDRESS_LENGTH, workBuffer + offset);
offset += ADDRESS_LENGTH; offset += ADDRESS_LENGTH;
uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE); chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
// this prints raw data, so to have a more meaningful print, display // this prints raw data, so to have a more meaningful print, display
// the buffer before the endianness swap // the buffer before the endianness swap
PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset)); PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset));
@@ -134,35 +137,18 @@ void handleProvideNFTInformation(uint8_t p1,
} }
offset += CHAIN_ID_SIZE; offset += CHAIN_ID_SIZE;
uint8_t keyId = workBuffer[offset]; if (workBuffer[offset] != valid_keyId) {
const uint8_t *rawKey; PRINTF("Unsupported KeyID %d\n", workBuffer[offset]);
uint8_t rawKeyLen;
PRINTF("KeyID: %d\n", keyId);
switch (keyId) {
#ifdef HAVE_NFT_STAGING_KEY
case STAGING_NFT_METADATA_KEY:
#endif
case PROD_NFT_METADATA_KEY:
rawKey = LEDGER_NFT_METADATA_PUBLIC_KEY;
rawKeyLen = sizeof(LEDGER_NFT_METADATA_PUBLIC_KEY);
break;
default:
PRINTF("KeyID %d not supported\n", keyId);
THROW(APDU_RESPONSE_INVALID_DATA); THROW(APDU_RESPONSE_INVALID_DATA);
break;
} }
PRINTF("RawKey: %.*H\n", rawKeyLen, rawKey);
offset += KEY_ID_SIZE; offset += KEY_ID_SIZE;
uint8_t algorithmId = workBuffer[offset]; if (workBuffer[offset] != ALGORITHM_ID_1) {
PRINTF("Algorithm: %d\n", algorithmId); PRINTF("Incorrect algorithmId %d\n", workBuffer[offset]);
if (algorithmId != ALGORITHM_ID_1) {
PRINTF("Incorrect algorithmId %d\n", algorithmId);
THROW(APDU_RESPONSE_INVALID_DATA); THROW(APDU_RESPONSE_INVALID_DATA);
} }
offset += ALGORITHM_ID_SIZE; offset += ALGORITHM_ID_SIZE;
PRINTF("hashing: %.*H\n", payloadSize, workBuffer); PRINTF("hashing: %.*H\n", payloadSize, workBuffer);
cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash)); cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash));
@@ -171,7 +157,7 @@ void handleProvideNFTInformation(uint8_t p1,
THROW(APDU_RESPONSE_INVALID_DATA); THROW(APDU_RESPONSE_INVALID_DATA);
} }
uint8_t signatureLen = workBuffer[offset]; signatureLen = workBuffer[offset];
PRINTF("Signature len: %d\n", signatureLen); PRINTF("Signature len: %d\n", signatureLen);
if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) { if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) {
PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n", PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n",
@@ -187,17 +173,21 @@ void handleProvideNFTInformation(uint8_t p1,
THROW(APDU_RESPONSE_INVALID_DATA); THROW(APDU_RESPONSE_INVALID_DATA);
} }
CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, rawKey, rawKeyLen, &nftKey)); error = check_signature_with_pubkey("NFT Info",
if (!cx_ecdsa_verify_no_throw(&nftKey,
hash, hash,
sizeof(hash), sizeof(hash),
(uint8_t *) workBuffer + offset, LEDGER_NFT_METADATA_PUBLIC_KEY,
signatureLen)) { sizeof(LEDGER_NFT_METADATA_PUBLIC_KEY),
#ifndef HAVE_BYPASS_SIGNATURES #ifdef HAVE_LEDGER_PKI
PRINTF("Invalid NFT signature\n"); CERTIFICATE_PUBLIC_KEY_USAGE_NFT_METADATA,
THROW(APDU_RESPONSE_INVALID_DATA);
#endif #endif
(uint8_t *) (workBuffer + offset),
signatureLen);
#ifndef HAVE_BYPASS_SIGNATURES
if (error != CX_OK) {
THROW(APDU_RESPONSE_INVALID_DATA);
} }
#endif
G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex; G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex;
validate_current_asset_info(); validate_current_asset_info();

View File

@@ -6,6 +6,9 @@
#include "plugin_utils.h" #include "plugin_utils.h"
#include "common_ui.h" #include "common_ui.h"
#include "os_io_seproxyhal.h" #include "os_io_seproxyhal.h"
#ifdef HAVE_LEDGER_PKI
#include "os_pki.h"
#endif
void handleSetExternalPlugin(uint8_t p1, void handleSetExternalPlugin(uint8_t p1,
uint8_t p2, uint8_t p2,
@@ -18,41 +21,43 @@ void handleSetExternalPlugin(uint8_t p1,
UNUSED(flags); UNUSED(flags);
PRINTF("Handling set Plugin\n"); PRINTF("Handling set Plugin\n");
uint8_t hash[INT256_LENGTH]; uint8_t hash[INT256_LENGTH];
cx_ecfp_public_key_t tokenKey;
uint8_t pluginNameLength = *workBuffer; uint8_t pluginNameLength = *workBuffer;
uint32_t params[2];
cx_err_t error = CX_INTERNAL_ERROR;
PRINTF("plugin Name Length: %d\n", pluginNameLength); PRINTF("plugin Name Length: %d\n", pluginNameLength);
const size_t payload_size = 1 + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE; const size_t payload_size = 1 + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE;
if (dataLength <= payload_size) { if (dataLength <= payload_size) {
PRINTF("data too small: expected at least %d got %d\n", payload_size, dataLength); PRINTF("data too small: expected at least %d got %d\n", payload_size, dataLength);
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
if (pluginNameLength + 1 > sizeof(dataContext.tokenContext.pluginName)) { if (pluginNameLength + 1 > sizeof(dataContext.tokenContext.pluginName)) {
PRINTF("name length too big: expected max %d, got %d\n", PRINTF("name length too big: expected max %d, got %d\n",
sizeof(dataContext.tokenContext.pluginName), sizeof(dataContext.tokenContext.pluginName),
pluginNameLength + 1); pluginNameLength + 1);
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
// check Ledger's signature over the payload // check Ledger's signature over the payload
cx_hash_sha256(workBuffer, payload_size, hash, sizeof(hash)); cx_hash_sha256(workBuffer, payload_size, hash, sizeof(hash));
CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1,
LEDGER_SIGNATURE_PUBLIC_KEY, error = check_signature_with_pubkey("External Plugin",
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
&tokenKey));
if (!cx_ecdsa_verify_no_throw(&tokenKey,
hash, hash,
sizeof(hash), sizeof(hash),
workBuffer + payload_size, LEDGER_SIGNATURE_PUBLIC_KEY,
dataLength - payload_size)) { sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
#ifndef HAVE_BYPASS_SIGNATURES #ifdef HAVE_LEDGER_PKI
PRINTF("Invalid plugin signature %.*H\n", CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META,
dataLength - payload_size,
workBuffer + payload_size);
THROW(0x6A80);
#endif #endif
(uint8_t *) (workBuffer + payload_size),
dataLength - payload_size);
#ifndef HAVE_BYPASS_SIGNATURES
if (error != CX_OK) {
THROW(APDU_RESPONSE_INVALID_DATA);
} }
#endif
// move on to the rest of the payload parsing // move on to the rest of the payload parsing
workBuffer++; workBuffer++;
@@ -63,7 +68,6 @@ void handleSetExternalPlugin(uint8_t p1,
PRINTF("Check external plugin %s\n", dataContext.tokenContext.pluginName); PRINTF("Check external plugin %s\n", dataContext.tokenContext.pluginName);
// Check if the plugin is present on the device // Check if the plugin is present on the device
uint32_t params[2];
params[0] = (uint32_t) dataContext.tokenContext.pluginName; params[0] = (uint32_t) dataContext.tokenContext.pluginName;
params[1] = ETH_PLUGIN_CHECK_PRESENCE; params[1] = ETH_PLUGIN_CHECK_PRESENCE;
BEGIN_TRY { BEGIN_TRY {

View File

@@ -9,6 +9,9 @@
#include "os_io_seproxyhal.h" #include "os_io_seproxyhal.h"
#include "network.h" #include "network.h"
#include "public_keys.h" #include "public_keys.h"
#ifdef HAVE_LEDGER_PKI
#include "os_pki.h"
#endif
// Supported internal plugins // Supported internal plugins
#define ERC721_STR "ERC721" #define ERC721_STR "ERC721"
@@ -82,53 +85,51 @@ void handleSetPlugin(uint8_t p1,
UNUSED(flags); UNUSED(flags);
PRINTF("Handling set Plugin\n"); PRINTF("Handling set Plugin\n");
uint8_t hash[INT256_LENGTH] = {0}; uint8_t hash[INT256_LENGTH] = {0};
cx_ecfp_public_key_t pluginKey = {0};
tokenContext_t *tokenContext = &dataContext.tokenContext; tokenContext_t *tokenContext = &dataContext.tokenContext;
size_t offset = 0; size_t offset = 0;
uint8_t pluginNameLength = 0;
size_t payloadSize = 0;
uint64_t chain_id = 0;
uint8_t signatureLen = 0;
cx_err_t error = CX_INTERNAL_ERROR;
#ifdef HAVE_NFT_STAGING_KEY
enum KeyId valid_keyId = TEST_PLUGIN_KEY;
#else
enum KeyId valid_keyId = PROD_PLUGIN_KEY;
#endif
enum KeyId keyId;
uint32_t params[2];
if (dataLength <= HEADER_SIZE) { if (dataLength <= HEADER_SIZE) {
PRINTF("Data too small for headers: expected at least %d, got %d\n", PRINTF("Data too small for headers: expected at least %d, got %d\n",
HEADER_SIZE, HEADER_SIZE,
dataLength); dataLength);
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
enum Type type = workBuffer[offset]; if (workBuffer[offset] != ETH_PLUGIN) {
PRINTF("Type: %d\n", type); PRINTF("Unsupported type %d\n", workBuffer[offset]);
switch (type) { THROW(APDU_RESPONSE_INVALID_DATA);
case ETH_PLUGIN:
break;
default:
PRINTF("Unsupported type %d\n", type);
THROW(0x6a80);
break;
} }
offset += TYPE_SIZE; offset += TYPE_SIZE;
uint8_t version = workBuffer[offset]; if (workBuffer[offset] != VERSION_1) {
PRINTF("version: %d\n", version); PRINTF("Unsupported version %d\n", workBuffer[offset]);
switch (version) { THROW(APDU_RESPONSE_INVALID_DATA);
case VERSION_1:
break;
default:
PRINTF("Unsupported version %d\n", version);
THROW(0x6a80);
break;
} }
offset += VERSION_SIZE; offset += VERSION_SIZE;
uint8_t pluginNameLength = workBuffer[offset]; pluginNameLength = workBuffer[offset];
offset += PLUGIN_NAME_LENGTH_SIZE; offset += PLUGIN_NAME_LENGTH_SIZE;
// Size of the payload (everything except the signature) // Size of the payload (everything except the signature)
size_t payloadSize = HEADER_SIZE + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE + payloadSize = HEADER_SIZE + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE + CHAIN_ID_SIZE +
CHAIN_ID_SIZE + KEY_ID_SIZE + ALGORITHM_ID_SIZE; KEY_ID_SIZE + ALGORITHM_ID_SIZE;
if (dataLength < payloadSize) { if (dataLength < payloadSize) {
PRINTF("Data too small for payload: expected at least %d, got %d\n", PRINTF("Data too small for payload: expected at least %d, got %d\n",
payloadSize, payloadSize,
dataLength); dataLength);
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
// `+ 1` because we want to add a null terminating character. // `+ 1` because we want to add a null terminating character.
@@ -136,7 +137,7 @@ void handleSetPlugin(uint8_t p1,
PRINTF("plugin name too big: expected max %d, got %d\n", PRINTF("plugin name too big: expected max %d, got %d\n",
sizeof(dataContext.tokenContext.pluginName), sizeof(dataContext.tokenContext.pluginName),
pluginNameLength + 1); pluginNameLength + 1);
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
// Safe because we've checked the size before. // Safe because we've checked the size before.
@@ -155,7 +156,7 @@ void handleSetPlugin(uint8_t p1,
PRINTF("Selector: %.*H\n", SELECTOR_SIZE, tokenContext->methodSelector); PRINTF("Selector: %.*H\n", SELECTOR_SIZE, tokenContext->methodSelector);
offset += SELECTOR_SIZE; offset += SELECTOR_SIZE;
uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE); chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
// this prints raw data, so to have a more meaningful print, display // this prints raw data, so to have a more meaningful print, display
// the buffer before the endianness swap // the buffer before the endianness swap
PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset)); PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset));
@@ -165,86 +166,71 @@ void handleSetPlugin(uint8_t p1,
} }
offset += CHAIN_ID_SIZE; offset += CHAIN_ID_SIZE;
enum KeyId keyId = workBuffer[offset]; keyId = workBuffer[offset];
uint8_t const *rawKey; if (keyId != valid_keyId) {
uint8_t rawKeyLen; PRINTF("Unsupported KeyID %d\n", keyId);
THROW(APDU_RESPONSE_INVALID_DATA);
PRINTF("KeyID: %d\n", keyId);
switch (keyId) {
#ifdef HAVE_NFT_STAGING_KEY
case TEST_PLUGIN_KEY:
#endif
case PROD_PLUGIN_KEY:
rawKey = LEDGER_NFT_SELECTOR_PUBLIC_KEY;
rawKeyLen = sizeof(LEDGER_NFT_SELECTOR_PUBLIC_KEY);
break;
default:
PRINTF("KeyID %d not supported\n", keyId);
THROW(0x6A80);
break;
} }
PRINTF("RawKey: %.*H\n", rawKeyLen, rawKey);
offset += KEY_ID_SIZE; offset += KEY_ID_SIZE;
uint8_t algorithmId = workBuffer[offset]; if (workBuffer[offset] != ECC_SECG_P256K1__ECDSA_SHA_256) {
PRINTF("Algorithm: %d\n", algorithmId); PRINTF("Incorrect algorithmId %d\n", workBuffer[offset]);
THROW(APDU_RESPONSE_INVALID_DATA);
if (algorithmId != ECC_SECG_P256K1__ECDSA_SHA_256) {
PRINTF("Incorrect algorithmId %d\n", algorithmId);
THROW(0x6a80);
} }
offset += ALGORITHM_ID_SIZE; offset += ALGORITHM_ID_SIZE;
PRINTF("hashing: %.*H\n", payloadSize, workBuffer); PRINTF("hashing: %.*H\n", payloadSize, workBuffer);
cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash)); cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash));
if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE) { if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE) {
PRINTF("Data too short to hold signature length\n"); PRINTF("Data too short to hold signature length\n");
THROW(0x6a80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
uint8_t signatureLen = workBuffer[offset]; signatureLen = workBuffer[offset];
PRINTF("Signature len: %d\n", signatureLen); PRINTF("Signature len: %d\n", signatureLen);
if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) { if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) {
PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n", PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n",
MIN_DER_SIG_SIZE, MIN_DER_SIG_SIZE,
MAX_DER_SIG_SIZE, MAX_DER_SIG_SIZE,
signatureLen); signatureLen);
THROW(0x6a80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
offset += SIGNATURE_LENGTH_SIZE; offset += SIGNATURE_LENGTH_SIZE;
if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE + signatureLen) { if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE + signatureLen) {
PRINTF("Signature could not fit in data\n"); PRINTF("Signature could not fit in data\n");
THROW(0x6a80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, rawKey, rawKeyLen, &pluginKey)); error = check_signature_with_pubkey("Set Plugin",
if (!cx_ecdsa_verify_no_throw(&pluginKey,
hash, hash,
sizeof(hash), sizeof(hash),
(unsigned char *) (workBuffer + offset), LEDGER_NFT_SELECTOR_PUBLIC_KEY,
signatureLen)) { sizeof(LEDGER_NFT_SELECTOR_PUBLIC_KEY),
#ifndef HAVE_BYPASS_SIGNATURES #ifdef HAVE_LEDGER_PKI
PRINTF("Invalid NFT signature\n"); CERTIFICATE_PUBLIC_KEY_USAGE_PLUGIN_METADATA,
THROW(0x6A80);
#endif #endif
(uint8_t *) (workBuffer + offset),
signatureLen);
#ifndef HAVE_BYPASS_SIGNATURES
if (error != CX_OK) {
THROW(APDU_RESPONSE_INVALID_DATA);
} }
#endif
pluginType = getPluginType(tokenContext->pluginName, pluginNameLength); pluginType = getPluginType(tokenContext->pluginName, pluginNameLength);
if (keyId == PROD_PLUGIN_KEY) { if (keyId == PROD_PLUGIN_KEY) {
if (pluginType != ERC721 && pluginType != ERC1155) { if (pluginType != ERC721 && pluginType != ERC1155) {
PRINTF("AWS key must only be used to set NFT internal plugins\n"); PRINTF("AWS key must only be used to set NFT internal plugins\n");
THROW(0x6A80); THROW(APDU_RESPONSE_INVALID_DATA);
} }
} }
switch (pluginType) { if (pluginType == EXTERNAL) {
case EXTERNAL: {
PRINTF("Check external plugin %s\n", tokenContext->pluginName); PRINTF("Check external plugin %s\n", tokenContext->pluginName);
// Check if the plugin is present on the device // Check if the plugin is present on the device
uint32_t params[2];
params[0] = (uint32_t) tokenContext->pluginName; params[0] = (uint32_t) tokenContext->pluginName;
params[1] = ETH_PLUGIN_CHECK_PRESENCE; params[1] = ETH_PLUGIN_CHECK_PRESENCE;
BEGIN_TRY { BEGIN_TRY {
@@ -260,10 +246,6 @@ void handleSetPlugin(uint8_t p1,
} }
} }
END_TRY; END_TRY;
break;
}
default:
break;
} }
G_io_apdu_buffer[(*tx)++] = 0x90; G_io_apdu_buffer[(*tx)++] = 0x90;

View File

@@ -12,6 +12,9 @@
#include "path.h" #include "path.h"
#include "ui_logic.h" #include "ui_logic.h"
#include "filtering.h" #include "filtering.h"
#ifdef HAVE_LEDGER_PKI
#include "os_pki.h"
#endif
#define FILT_MAGIC_MESSAGE_INFO 183 #define FILT_MAGIC_MESSAGE_INFO 183
#define FILT_MAGIC_AMOUNT_JOIN_TOKEN 11 #define FILT_MAGIC_AMOUNT_JOIN_TOKEN 11
@@ -95,26 +98,26 @@ static bool sig_verif_start(cx_sha256_t *hash_ctx, uint8_t magic) {
*/ */
static bool sig_verif_end(cx_sha256_t *hash_ctx, const uint8_t *sig, uint8_t sig_length) { static bool sig_verif_end(cx_sha256_t *hash_ctx, const uint8_t *sig, uint8_t sig_length) {
uint8_t hash[INT256_LENGTH]; uint8_t hash[INT256_LENGTH];
cx_ecfp_public_key_t verifying_key;
cx_err_t error = CX_INTERNAL_ERROR; cx_err_t error = CX_INTERNAL_ERROR;
bool ret_code = false;
// Finalize hash // Finalize hash
CX_CHECK(cx_hash_no_throw((cx_hash_t *) hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); CX_CHECK(cx_hash_no_throw((cx_hash_t *) hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH));
CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, CX_CHECK(check_signature_with_pubkey("EIP712 Filtering",
hash,
sizeof(hash),
LEDGER_SIGNATURE_PUBLIC_KEY, LEDGER_SIGNATURE_PUBLIC_KEY,
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
&verifying_key)); #ifdef HAVE_LEDGER_PKI
if (!cx_ecdsa_verify_no_throw(&verifying_key, hash, sizeof(hash), sig, sig_length)) { CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META,
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid EIP-712 filtering signature\n");
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
#endif #endif
} (uint8_t *) (sig),
return true; sig_length));
ret_code = true;
end: end:
return false; return ret_code;
} }
/** /**

View File

@@ -13,6 +13,7 @@ disable = C0114, # missing-module-docstring
R0912, # too-many-branches R0912, # too-many-branches
R0913, # too-many-arguments R0913, # too-many-arguments
R0914, # too-many-locals R0914, # too-many-locals
R0915, # too-many-statements
W0603, # global-statement W0603, # global-statement
E0401 # import-error E0401 # import-error
extension-pkg-whitelist=hid extension-pkg-whitelist=hid

View File

@@ -34,7 +34,7 @@ def common_tx_params() -> dict:
abi=json.load(file), abi=json.load(file),
address=None address=None
) )
data = contract.encodeABI("approve", [ data = contract.encode_abi("approve", [
# Uniswap Protocol: Permit2 # Uniswap Protocol: Permit2
bytes.fromhex("000000000022d473030f116ddee9f6b43ac78ba3"), bytes.fromhex("000000000022d473030f116ddee9f6b43ac78ba3"),
Web3.to_wei("2", "ether") Web3.to_wei("2", "ether")

View File

@@ -34,6 +34,7 @@ def common(firmware: Firmware, app_client: EthAppClient) -> int:
if firmware == Firmware.NANOS: if firmware == Firmware.NANOS:
pytest.skip("Not supported on LNS") pytest.skip("Not supported on LNS")
challenge = app_client.get_challenge() challenge = app_client.get_challenge()
return ResponseParser.challenge(challenge.data) return ResponseParser.challenge(challenge.data)

View File

@@ -5,7 +5,6 @@ from ragger.backend import BackendInterface
from client.client import EthAppClient, StatusWord from client.client import EthAppClient, StatusWord
def test_provide_erc20_token(backend: BackendInterface): def test_provide_erc20_token(backend: BackendInterface):
app_client = EthAppClient(backend) app_client = EthAppClient(backend)
@@ -21,7 +20,7 @@ def test_provide_erc20_token_error(backend: BackendInterface):
addr = bytes.fromhex("e41d2489571d322189246dafa5ebde1f4699f498") addr = bytes.fromhex("e41d2489571d322189246dafa5ebde1f4699f498")
sign = bytes.fromhex("deadbeef") sign = bytes.fromhex("deadbeef")
with pytest.raises(ExceptionRAPDU) as e: with pytest.raises(ExceptionRAPDU) as err:
app_client.provide_token_metadata("ZRX", addr, 18, 1, sign) app_client.provide_token_metadata("ZRX", addr, 18, 1, sign)
assert e.value.status == StatusWord.INVALID_DATA assert err.value.status == StatusWord.INVALID_DATA

View File

@@ -21,7 +21,7 @@ def with_chaincode_fixture(request) -> bool:
return request.param return request.param
@pytest.fixture(name="chain", params=[None, 1, 2, 5, 137]) @pytest.fixture(name="chain", params=[None, 1, 2, 5, 137, 138])
def chain_fixture(request) -> Optional[int]: def chain_fixture(request) -> Optional[int]:
return request.param return request.param

View File

@@ -65,11 +65,12 @@ def common_test_nft(firmware: Firmware,
pass pass
_, DEVICE_ADDR, _ = ResponseParser.pk_addr(app_client.response().data) _, DEVICE_ADDR, _ = ResponseParser.pk_addr(app_client.response().data)
data = collec.contract.encodeABI(action.fn_name, action.fn_args) data = collec.contract.encode_abi(action.fn_name, action.fn_args)
app_client.set_plugin(plugin_name, app_client.set_plugin(plugin_name,
collec.addr, collec.addr,
get_selector_from_data(data), get_selector_from_data(data),
collec.chain_id) collec.chain_id)
app_client.provide_nft_metadata(collec.name, collec.addr, collec.chain_id) app_client.provide_nft_metadata(collec.name, collec.addr, collec.chain_id)
tx_params = { tx_params = {
"nonce": NONCE, "nonce": NONCE,