diff --git a/client/src/ledger_app_clients/ethereum/client.py b/client/src/ledger_app_clients/ethereum/client.py index 11325fac4..8fdc693af 100644 --- a/client/src/ledger_app_clients/ethereum/client.py +++ b/client/src/ledger_app_clients/ethereum/client.py @@ -255,7 +255,7 @@ def perform_privacy_operation(self, bip32_path, pubkey)) - def _provide_trusted_name_common(self, payload: bytes) -> RAPDU: + def _provide_trusted_name_common(self, payload: bytes, name_source: TrustedNameSource) -> RAPDU: if self._pki_client is None: print(f"Ledger-PKI Not supported on '{self._firmware.name}'") else: @@ -272,10 +272,16 @@ def _provide_trusted_name_common(self, payload: bytes) -> RAPDU: self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu)) payload += format_tlv(FieldTag.STRUCT_TYPE, 3) # TrustedName - payload += format_tlv(FieldTag.SIGNER_KEY_ID, 0) # test key + if name_source == TrustedNameSource.CAL: + key_id = 6 + key = Key.CAL + else: + key_id = 3 + key = Key.TRUSTED_NAME + payload += format_tlv(FieldTag.SIGNER_KEY_ID, key_id) # test key payload += format_tlv(FieldTag.SIGNER_ALGO, 1) # secp256k1 payload += format_tlv(FieldTag.DER_SIGNATURE, - sign_data(Key.TRUSTED_NAME, payload)) + sign_data(key, payload)) chunks = self._cmd_builder.provide_trusted_name(payload) for chunk in chunks[:-1]: self._exchange(chunk) @@ -287,7 +293,7 @@ def provide_trusted_name_v1(self, addr: bytes, name: str, challenge: int) -> RAP payload += format_tlv(FieldTag.COIN_TYPE, 0x3c) # ETH in slip-44 payload += format_tlv(FieldTag.TRUSTED_NAME, name) payload += format_tlv(FieldTag.ADDRESS, addr) - return self._provide_trusted_name_common(payload) + return self._provide_trusted_name_common(payload, TrustedNameSource.ENS) def provide_trusted_name_v2(self, addr: bytes, @@ -311,7 +317,7 @@ def provide_trusted_name_v2(self, if not_valid_after is not None: assert len(not_valid_after) == 3 payload += format_tlv(FieldTag.NOT_VALID_AFTER, struct.pack("BBB", *not_valid_after)) - return self._provide_trusted_name_common(payload) + return self._provide_trusted_name_common(payload, name_source) def set_plugin(self, plugin_name: str, diff --git a/src_bagl/ui_flow_signTx.c b/src_bagl/ui_flow_signTx.c index 2218cf44c..d25e6c34e 100644 --- a/src_bagl/ui_flow_signTx.c +++ b/src_bagl/ui_flow_signTx.c @@ -267,8 +267,10 @@ void ux_approve_tx(bool fromPlugin) { } #ifdef HAVE_TRUSTED_NAME uint64_t chain_id = get_tx_chain_id(); - e_name_type type = TYPE_ACCOUNT; - if (has_trusted_name(1, &type, &chain_id, tmpContent.txContent.destination)) { + e_name_type type = TN_TYPE_ACCOUNT; + e_name_source source = TN_SOURCE_ENS; + if (get_trusted_name(1, &type, 1, &source, &chain_id, tmpContent.txContent.destination) != + NULL) { ux_approval_tx_flow[step++] = &ux_trusted_name_step; if (N_storage.verbose_trusted_name) { ux_approval_tx_flow[step++] = &ux_approval_to_step; diff --git a/src_features/provideTrustedName/cmd_provide_trusted_name.c b/src_features/provideTrustedName/cmd_provide_trusted_name.c index 23d5cf168..a540c2369 100644 --- a/src_features/provideTrustedName/cmd_provide_trusted_name.c +++ b/src_features/provideTrustedName/cmd_provide_trusted_name.c @@ -63,7 +63,7 @@ typedef enum { NFT_ID = 0x72, } e_tlv_tag; -typedef enum { KEY_ID_TEST = 0x00, KEY_ID_PROD = 0x03 } e_key_id; +typedef enum { TN_KEY_ID_DOMAIN_SVC = 0x03, TN_KEY_ID_CAL = 0x06 } e_tn_key_id; typedef struct { uint8_t *buf; @@ -90,7 +90,7 @@ typedef struct { } s_trusted_name_info; typedef struct { - e_key_id key_id; + e_tn_key_id key_id; uint8_t input_sig_size; const uint8_t *input_sig; cx_sha256_t hash_ctx; @@ -110,10 +110,56 @@ static s_tlv_payload g_tlv_payload = {0}; static s_trusted_name_info g_trusted_name_info = {0}; char g_trusted_name[TRUSTED_NAME_MAX_LENGTH + 1]; +static bool matching_type(e_name_type type, uint8_t type_count, const e_name_type *types) { + for (int i = 0; i < type_count; ++i) { + if (type == types[i]) return true; + } + return false; +} + +static bool matching_source(e_name_source source, + uint8_t source_count, + const e_name_source *sources) { + for (int i = 0; i < source_count; ++i) { + if (source == sources[i]) return true; + } + return false; +} + +static bool matching_trusted_name(const s_trusted_name_info *trusted_name, + uint8_t type_count, + const e_name_type *types, + uint8_t source_count, + const e_name_source *sources, + const uint64_t *chain_id, + const uint8_t *addr) { + switch (trusted_name->struct_version) { + case 1: + if (!matching_type(TN_TYPE_ACCOUNT, type_count, types)) { + return false; + } + if (!chain_is_ethereum_compatible(chain_id)) { + return false; + } + break; + case 2: + if (!matching_type(trusted_name->name_type, type_count, types)) { + return false; + } + if (!matching_source(trusted_name->name_source, source_count, sources)) { + return false; + } + if (*chain_id != trusted_name->chain_id) { + return false; + } + break; + } + return memcmp(addr, trusted_name->addr, ADDRESS_LENGTH) == 0; +} + /** * Checks if a trusted name matches the given parameters * - * Does not care about the trusted name source for now. * Always wipes the content of \ref g_trusted_name_info * * @param[in] types_count number of given trusted name types @@ -122,36 +168,23 @@ char g_trusted_name[TRUSTED_NAME_MAX_LENGTH + 1]; * @param[in] addr given address * @return whether there is or not */ -bool has_trusted_name(uint8_t types_count, - const e_name_type *types, - const uint64_t *chain_id, - const uint8_t *addr) { - bool ret = false; +const char *get_trusted_name(uint8_t type_count, + const e_name_type *types, + uint8_t source_count, + const e_name_source *sources, + const uint64_t *chain_id, + const uint8_t *addr) { + const char *ret = NULL; if (g_trusted_name_info.rcv_flags != 0) { - for (int i = 0; i < types_count; ++i) { - switch (g_trusted_name_info.struct_version) { - case 1: - if (types[i] == TYPE_ACCOUNT) { - // Check if chain ID is known to be Ethereum-compatible (same derivation - // path) - if ((chain_is_ethereum_compatible(chain_id)) && - (memcmp(addr, g_trusted_name_info.addr, ADDRESS_LENGTH) == 0)) { - ret = true; - } - } - break; - case 2: - if (types[i] == g_trusted_name_info.name_type) { - if (*chain_id == g_trusted_name_info.chain_id) { - ret = true; - } - } - break; - default: - ret = false; - } - if (ret) break; + if (matching_trusted_name(&g_trusted_name_info, + type_count, + types, + source_count, + sources, + chain_id, + addr)) { + ret = g_trusted_name_info.name; } explicit_bzero(&g_trusted_name_info, sizeof(g_trusted_name_info)); } @@ -378,7 +411,7 @@ static bool handle_trusted_name(const s_tlv_data *data, return false; } if ((trusted_name_info->struct_version == 1) || - (trusted_name_info->name_type == TYPE_ACCOUNT)) { + (trusted_name_info->name_type == TN_TYPE_ACCOUNT)) { // TODO: Remove once other domain name providers are supported if ((data->length < 5) || (strncmp(".eth", (char *) &data->value[data->length - 4], 4) != 0)) { @@ -474,10 +507,13 @@ static bool handle_trusted_name_type(const s_tlv_data *data, return false; } switch (value) { - case TYPE_ACCOUNT: - case TYPE_CONTRACT: + case TN_TYPE_ACCOUNT: + case TN_TYPE_CONTRACT: break; - case TYPE_NFT: + case TN_TYPE_NFT_COLLECTION: + case TN_TYPE_TOKEN: + case TN_TYPE_WALLET: + case TN_TYPE_CONTEXT_ADDRESS: default: PRINTF("Error: unsupported trusted name type (%u)!\n", value); return false; @@ -505,13 +541,14 @@ static bool handle_trusted_name_source(const s_tlv_data *data, return false; } switch (value) { - case SOURCE_CAL: - case SOURCE_ENS: + case TN_SOURCE_CAL: + case TN_SOURCE_ENS: break; - case SOURCE_LAB: - case SOURCE_UD: - case SOURCE_FN: - case SOURCE_DNS: + case TN_SOURCE_LAB: + case TN_SOURCE_UD: + case TN_SOURCE_FN: + case TN_SOURCE_DNS: + case TN_SOURCE_DYNAMIC_RESOLVER: default: PRINTF("Error: unsupported trusted name source (%u)!\n", value); return false; @@ -555,16 +592,22 @@ static bool handle_nft_id(const s_tlv_data *data, static bool verify_signature(const s_sig_ctx *sig_ctx) { uint8_t hash[INT256_LENGTH]; cx_err_t error = CX_INTERNAL_ERROR; -#ifdef HAVE_TRUSTED_NAME_TEST_KEY - e_key_id valid_key_id = KEY_ID_TEST; -#else - e_key_id valid_key_id = KEY_ID_PROD; -#endif bool ret_code = false; + const uint8_t *pk; + size_t pk_size; - if (sig_ctx->key_id != valid_key_id) { - PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id); - return false; + switch (sig_ctx->key_id) { + case TN_KEY_ID_DOMAIN_SVC: + pk = TRUSTED_NAME_PUB_KEY; + pk_size = sizeof(TRUSTED_NAME_PUB_KEY); + break; + case TN_KEY_ID_CAL: + pk = LEDGER_SIGNATURE_PUBLIC_KEY; + pk_size = sizeof(LEDGER_SIGNATURE_PUBLIC_KEY); + break; + default: + PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id); + return false; } CX_CHECK( @@ -573,10 +616,10 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { CX_CHECK(check_signature_with_pubkey("Domain Name", hash, sizeof(hash), - TRUSTED_NAME_PUB_KEY, - sizeof(TRUSTED_NAME_PUB_KEY), + pk, + pk_size, #ifdef HAVE_LEDGER_PKI - CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META, + CERTIFICATE_PUBLIC_KEY_USAGE_TRUSTED_NAME, #endif (uint8_t *) (sig_ctx->input_sig), sig_ctx->input_sig_size)); @@ -651,8 +694,8 @@ static bool verify_struct(const s_trusted_name_info *trusted_name_info) { return false; } switch (trusted_name_info->name_type) { - case TYPE_ACCOUNT: - if (trusted_name_info->name_source == SOURCE_CAL) { + case TN_TYPE_ACCOUNT: + if (trusted_name_info->name_source == TN_SOURCE_CAL) { PRINTF("Error: cannot accept an account name from the CAL!\n"); return false; } @@ -661,8 +704,8 @@ static bool verify_struct(const s_trusted_name_info *trusted_name_info) { return false; } break; - case TYPE_CONTRACT: - if (trusted_name_info->name_source != SOURCE_CAL) { + case TN_TYPE_CONTRACT: + if (trusted_name_info->name_source != TN_SOURCE_CAL) { PRINTF("Error: cannot accept a contract name from given source (%u)!\n", trusted_name_info->name_source); return false; diff --git a/src_features/provideTrustedName/trusted_name.h b/src_features/provideTrustedName/trusted_name.h index 142a5b7b0..ad7d05a7d 100644 --- a/src_features/provideTrustedName/trusted_name.h +++ b/src_features/provideTrustedName/trusted_name.h @@ -9,24 +9,35 @@ #define TRUSTED_NAME_MAX_LENGTH 30 typedef enum { - TYPE_ACCOUNT = 1, - TYPE_CONTRACT, - TYPE_NFT, + TN_TYPE_ACCOUNT = 1, + TN_TYPE_CONTRACT, + TN_TYPE_NFT_COLLECTION, + TN_TYPE_TOKEN, + TN_TYPE_WALLET, + TN_TYPE_CONTEXT_ADDRESS, + _TN_TYPE_COUNT_, } e_name_type; +// because the enum does not start at 0 +#define TN_TYPE_COUNT (_TN_TYPE_COUNT_ - TN_TYPE_ACCOUNT) + typedef enum { - SOURCE_LAB = 0, - SOURCE_CAL, - SOURCE_ENS, - SOURCE_UD, - SOURCE_FN, - SOURCE_DNS, + TN_SOURCE_LAB = 0, + TN_SOURCE_CAL, + TN_SOURCE_ENS, + TN_SOURCE_UD, + TN_SOURCE_FN, + TN_SOURCE_DNS, + TN_SOURCE_DYNAMIC_RESOLVER, + TN_SOURCE_COUNT, } e_name_source; -bool has_trusted_name(uint8_t types_count, - const e_name_type *types, - const uint64_t *chain_id, - const uint8_t *addr); +const char *get_trusted_name(uint8_t type_count, + const e_name_type *types, + uint8_t source_count, + const e_name_source *sources, + const uint64_t *chain_id, + const uint8_t *addr); uint16_t handle_provide_trusted_name(uint8_t p1, const uint8_t *data, uint8_t length); extern char g_trusted_name[TRUSTED_NAME_MAX_LENGTH + 1]; diff --git a/src_features/signMessageEIP712/filtering.c b/src_features/signMessageEIP712/filtering.c index bb43b36a4..5a03e8401 100644 --- a/src_features/signMessageEIP712/filtering.c +++ b/src_features/signMessageEIP712/filtering.c @@ -342,9 +342,9 @@ bool filtering_trusted_name(const uint8_t *payload, uint32_t *path_crc) { uint8_t name_len; const char *name; - uint8_t types_count; + uint8_t type_count; e_name_type *types; - uint8_t sources_count; + uint8_t source_count; e_name_source *sources; uint8_t sig_len; const uint8_t *sig; @@ -365,48 +365,30 @@ bool filtering_trusted_name(const uint8_t *payload, } name = (char *) &payload[offset]; offset += name_len; - if ((offset + sizeof(types_count)) > length) { + if ((offset + sizeof(type_count)) > length) { return false; } - types_count = payload[offset++]; - if ((offset + types_count) > length) { + type_count = payload[offset++]; + if (type_count > TN_TYPE_COUNT) { + return false; + } + if ((offset + type_count) > length) { return false; } types = (e_name_type *) &payload[offset]; - // sanity check - for (int i = 0; i < types_count; ++i) { - switch (types[i]) { - case TYPE_ACCOUNT: - case TYPE_CONTRACT: - break; - default: - return false; - } + offset += type_count; + if ((offset + sizeof(source_count)) > length) { + return false; } - offset += types_count; - if ((offset + sizeof(sources_count)) > length) { + source_count = payload[offset++]; + if (source_count > TN_SOURCE_COUNT) { return false; } - sources_count = payload[offset++]; - if ((offset + sources_count) > length) { + if ((offset + source_count) > length) { return false; } sources = (e_name_source *) &payload[offset]; - // sanity check - for (int i = 0; i < sources_count; ++i) { - switch (sources[i]) { - case SOURCE_LAB: - case SOURCE_CAL: - case SOURCE_ENS: - case SOURCE_UD: - case SOURCE_FN: - case SOURCE_DNS: - break; - default: - return false; - } - } - offset += sources_count; + offset += source_count; // if ((offset + sizeof(sig_len)) > length) { return false; @@ -424,8 +406,8 @@ bool filtering_trusted_name(const uint8_t *payload, } hash_filtering_path((cx_hash_t *) &hash_ctx, discarded, path_crc); hash_nbytes((uint8_t *) name, sizeof(char) * name_len, (cx_hash_t *) &hash_ctx); - hash_nbytes(types, types_count, (cx_hash_t *) &hash_ctx); - hash_nbytes(sources, sources_count, (cx_hash_t *) &hash_ctx); + hash_nbytes(types, type_count, (cx_hash_t *) &hash_ctx); + hash_nbytes(sources, source_count, (cx_hash_t *) &hash_ctx); if (!sig_verif_end(&hash_ctx, sig, sig_len)) { return false; } @@ -438,7 +420,7 @@ bool filtering_trusted_name(const uint8_t *payload, ui_712_set_title(name, name_len); } ui_712_flag_field(true, name_len > 0, false, false, true); - ui_712_set_trusted_name_requirements(types_count, types); + ui_712_set_trusted_name_requirements(type_count, types, source_count, sources); return true; } #endif // HAVE_TRUSTED_NAME diff --git a/src_features/signMessageEIP712/ui_logic.c b/src_features/signMessageEIP712/ui_logic.c index d0462f61b..901e9c637 100644 --- a/src_features/signMessageEIP712/ui_logic.c +++ b/src_features/signMessageEIP712/ui_logic.c @@ -65,7 +65,10 @@ typedef struct { uint8_t discarded_path_length; char discarded_path[255]; #ifdef HAVE_TRUSTED_NAME - e_name_type name_types; + uint8_t tn_type_count; + uint8_t tn_source_count; + e_name_type tn_types[TN_TYPE_COUNT]; + e_name_source tn_sources[TN_SOURCE_COUNT]; #endif #ifdef SCREEN_SIZE_WALLET char ui_pairs_buffer[(SHARED_CTX_FIELD_1_SIZE + SHARED_CTX_FIELD_2_SIZE) * 2]; @@ -530,20 +533,15 @@ static bool update_amount_join(const uint8_t *data, uint8_t length) { * @return whether it was successful or not */ static bool ui_712_format_trusted_name(const uint8_t *data, uint8_t length) { - uint8_t types_count = 0; - e_name_type types[8]; - uint8_t types_bak = ui_ctx->name_types; - if (length != ADDRESS_LENGTH) { return false; } - for (int i = 0; types_bak > 0; ++i) { - if (types_bak & 1) { - types[types_count++] = i; - } - types_bak >>= 1; - } - if (has_trusted_name(types_count, types, &eip712_context->chain_id, data)) { + if (get_trusted_name(ui_ctx->tn_type_count, + ui_ctx->tn_types, + ui_ctx->tn_source_count, + ui_ctx->tn_sources, + &eip712_context->chain_id, + data) != NULL) { strlcpy(strings.tmp.tmp, g_trusted_name, sizeof(strings.tmp.tmp)); } return true; @@ -924,12 +922,14 @@ const char *ui_712_get_discarded_path(uint8_t *length) { } #ifdef HAVE_TRUSTED_NAME -void ui_712_set_trusted_name_requirements(uint8_t types_count, const e_name_type *types) { - // pack into one byte to save on space - ui_ctx->name_types = 0; - for (int i = 0; i < types_count; ++i) { - ui_ctx->name_types |= (1 << types[i]); - } +void ui_712_set_trusted_name_requirements(uint8_t type_count, + const e_name_type *types, + uint8_t source_count, + const e_name_source *sources) { + ui_ctx->tn_type_count = type_count; + memcpy(ui_ctx->tn_types, types, type_count); + ui_ctx->tn_source_count = source_count; + memcpy(ui_ctx->tn_sources, sources, source_count); } #endif diff --git a/src_features/signMessageEIP712/ui_logic.h b/src_features/signMessageEIP712/ui_logic.h index d64e47f32..035c42746 100644 --- a/src_features/signMessageEIP712/ui_logic.h +++ b/src_features/signMessageEIP712/ui_logic.h @@ -52,7 +52,10 @@ bool ui_712_push_new_filter_path(uint32_t path_crc); void ui_712_set_discarded_path(const char *path, uint8_t length); const char *ui_712_get_discarded_path(uint8_t *length); #ifdef HAVE_TRUSTED_NAME -void ui_712_set_trusted_name_requirements(uint8_t types_count, const e_name_type *types); +void ui_712_set_trusted_name_requirements(uint8_t type_count, + const e_name_type *types, + uint8_t source_count, + const e_name_source *sources); #endif #ifdef SCREEN_SIZE_WALLET char *get_ui_pairs_buffer(size_t *size); diff --git a/src_nbgl/ui_approve_tx.c b/src_nbgl/ui_approve_tx.c index 6431218b9..300b4fa7c 100644 --- a/src_nbgl/ui_approve_tx.c +++ b/src_nbgl/ui_approve_tx.c @@ -148,9 +148,10 @@ static uint8_t setTagValuePairs(void) { #ifdef HAVE_TRUSTED_NAME uint64_t chain_id = get_tx_chain_id(); - e_name_type type = TYPE_ACCOUNT; + e_name_type type = TN_TYPE_ACCOUNT; + e_name_source source = TN_SOURCE_ENS; tx_approval_context.trusted_name_match = - has_trusted_name(1, &type, &chain_id, tmpContent.txContent.destination); + get_trusted_name(1, &type, 1, &source, &chain_id, tmpContent.txContent.destination); if (tx_approval_context.trusted_name_match) { pairs[nbPairs].item = "To (domain)"; pairs[nbPairs].value = g_trusted_name; diff --git a/tests/ragger/test_eip712.py b/tests/ragger/test_eip712.py index 7713883de..6904709cb 100644 --- a/tests/ragger/test_eip712.py +++ b/tests/ragger/test_eip712.py @@ -763,7 +763,7 @@ def test_eip712_advanced_trusted_name(firmware: Firmware, "type": "trusted_name", "name": "Validator", "tn_type": filt_tn_types, - "tn_source": [TrustedNameSource.CAL], + "tn_source": [TrustedNameSource.CAL, TrustedNameSource.ENS], }, "enable": { "type": "raw",