Skip to content

Commit

Permalink
Merge pull request #698 from LedgerHQ/feat/apa/trusted_name_changes
Browse files Browse the repository at this point in the history
Trusted name misc changes & fixes
  • Loading branch information
apaillier-ledger authored Dec 13, 2024
2 parents ef0839b + d6ac35f commit 2ae8e0d
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 134 deletions.
16 changes: 11 additions & 5 deletions client/src/ledger_app_clients/ethereum/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
Expand All @@ -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,
Expand All @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions src_bagl/ui_flow_signTx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
155 changes: 99 additions & 56 deletions src_features/provideTrustedName/cmd_provide_trusted_name.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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));
}
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand All @@ -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));
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down
37 changes: 24 additions & 13 deletions src_features/provideTrustedName/trusted_name.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
Loading

0 comments on commit 2ae8e0d

Please sign in to comment.