EIP712 filtering, added new APDUs
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#define INS_PERFORM_PRIVACY_OPERATION 0x18
|
||||
#define INS_EIP712_STRUCT_DEF 0x1A
|
||||
#define INS_EIP712_STRUCT_IMPL 0x1C
|
||||
#define INS_EIP712_FILTERING 0x1E
|
||||
#define P1_CONFIRM 0x01
|
||||
#define P1_NON_CONFIRM 0x00
|
||||
#define P2_NO_CHAINCODE 0x00
|
||||
@@ -172,8 +173,11 @@ void handleStarkwareUnsafeSign(uint8_t p1,
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EIP712_FULL_SUPPORT
|
||||
bool handle_eip712_struct_def(const uint8_t *const apdu_buf);
|
||||
bool handle_eip712_struct_impl(const uint8_t *const apdu_buf);
|
||||
bool handle_eip712_sign(const uint8_t *const apdu_buf);
|
||||
bool handle_eip712_filtering(const uint8_t *const apdu_buf);
|
||||
#endif // HAVE_EIP712_FULL_SUPPORT
|
||||
|
||||
#endif // _APDU_CONSTANTS_H_
|
||||
|
||||
@@ -717,6 +717,11 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
handle_eip712_struct_impl(G_io_apdu_buffer);
|
||||
break;
|
||||
|
||||
case INS_EIP712_FILTERING:
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
handle_eip712_filtering(G_io_apdu_buffer);
|
||||
break;
|
||||
#endif // HAVE_EIP712_FULL_SUPPORT
|
||||
|
||||
#if 0
|
||||
|
||||
@@ -55,7 +55,6 @@ bool eip712_context_init(void)
|
||||
|
||||
// create len(types)
|
||||
*(eip712_context->structs_array) = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,11 +34,16 @@ typedef enum
|
||||
// APDUs P1
|
||||
#define P1_COMPLETE 0x00
|
||||
#define P1_PARTIAL 0xFF
|
||||
#define P1_ACTIVATE 0x00
|
||||
#define P1_CONTRACT_NAME 0x0F
|
||||
#define P1_FIELD_NAME 0xFF
|
||||
|
||||
// APDUs P2
|
||||
#define P2_NAME 0x00
|
||||
#define P2_ARRAY 0x0F
|
||||
#define P2_FIELD 0xFF
|
||||
#define P2_KEY 0x00
|
||||
#define P2_VALUE 0xFF
|
||||
|
||||
// TypeDesc masks
|
||||
#define TYPE_MASK (0xF)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "shared_context.h"
|
||||
#include "ui_logic.h"
|
||||
#include "common_712.h"
|
||||
#include "path.h"
|
||||
|
||||
|
||||
// lib functions
|
||||
@@ -440,6 +441,277 @@ bool handle_eip712_struct_impl(const uint8_t *const apdu_buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool verify_contract_name_signature(uint8_t dname_length,
|
||||
const char *const dname,
|
||||
uint8_t sig_length,
|
||||
const uint8_t *const sig)
|
||||
{
|
||||
uint8_t hash[INT256_LENGTH];
|
||||
cx_ecfp_public_key_t verifying_key;
|
||||
cx_sha256_t hash_ctx;
|
||||
|
||||
cx_sha256_init(&hash_ctx);
|
||||
// Contract address
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
0,
|
||||
eip712_context->contract_addr,
|
||||
sizeof(eip712_context->contract_addr),
|
||||
NULL,
|
||||
0);
|
||||
|
||||
// Display name length
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
0,
|
||||
&dname_length,
|
||||
sizeof(dname_length),
|
||||
NULL,
|
||||
0);
|
||||
|
||||
// Display name
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
0,
|
||||
(uint8_t*)dname,
|
||||
sizeof(char) * dname_length,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
// Finalize hash
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
CX_LAST,
|
||||
NULL,
|
||||
0,
|
||||
hash,
|
||||
sizeof(hash));
|
||||
|
||||
cx_ecfp_init_public_key(CX_CURVE_256K1,
|
||||
LEDGER_SIGNATURE_PUBLIC_KEY,
|
||||
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
|
||||
&verifying_key);
|
||||
if (!cx_ecdsa_verify(&verifying_key,
|
||||
CX_LAST,
|
||||
CX_SHA256,
|
||||
hash,
|
||||
sizeof(hash),
|
||||
sig,
|
||||
sig_length))
|
||||
{
|
||||
#ifndef HAVE_BYPASS_SIGNATURES
|
||||
PRINTF("Invalid EIP-712 contract filtering signature\n");
|
||||
//return false; // TODO: Uncomment
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool verify_field_name_signature(uint8_t dname_length,
|
||||
const char *const dname,
|
||||
uint8_t sig_length,
|
||||
const uint8_t *const sig)
|
||||
{
|
||||
const void *field_ptr;
|
||||
const char *key;
|
||||
uint8_t key_len;
|
||||
uint8_t hash[INT256_LENGTH];
|
||||
cx_ecfp_public_key_t verifying_key;
|
||||
cx_sha256_t hash_ctx;
|
||||
|
||||
cx_sha256_init(&hash_ctx);
|
||||
// Contract address
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
0,
|
||||
eip712_context->contract_addr,
|
||||
sizeof(eip712_context->contract_addr),
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if ((field_ptr = path_get_field()) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((key = get_struct_field_keyname(field_ptr, &key_len)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Key length
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
0,
|
||||
&key_len,
|
||||
sizeof(key_len),
|
||||
NULL,
|
||||
0);
|
||||
|
||||
// Key
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
0,
|
||||
(uint8_t*)key,
|
||||
sizeof(char) * key_len,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
// Display name length
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
0,
|
||||
&dname_length,
|
||||
sizeof(dname_length),
|
||||
NULL,
|
||||
0);
|
||||
|
||||
// Display name
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
0,
|
||||
(uint8_t*)dname,
|
||||
sizeof(char) * dname_length,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
// Finalize hash
|
||||
cx_hash((cx_hash_t*)&hash_ctx,
|
||||
CX_LAST,
|
||||
NULL,
|
||||
0,
|
||||
hash,
|
||||
INT256_LENGTH);
|
||||
|
||||
cx_ecfp_init_public_key(CX_CURVE_256K1,
|
||||
LEDGER_SIGNATURE_PUBLIC_KEY,
|
||||
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
|
||||
&verifying_key);
|
||||
if (!cx_ecdsa_verify(&verifying_key,
|
||||
CX_LAST,
|
||||
CX_SHA256,
|
||||
hash,
|
||||
sizeof(hash),
|
||||
sig,
|
||||
sig_length))
|
||||
{
|
||||
#ifndef HAVE_BYPASS_SIGNATURES
|
||||
PRINTF("Invalid EIP-712 field filtering signature\n");
|
||||
//return false; // TODO: Uncomment
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool provide_contract_name(const uint8_t *const payload, uint8_t length)
|
||||
{
|
||||
bool ret = false;
|
||||
uint8_t dname_len;
|
||||
const char *dname;
|
||||
uint8_t sig_len;
|
||||
const uint8_t *sig;
|
||||
|
||||
if ((length > 0) && (path_get_root_type() == ROOT_DOMAIN))
|
||||
{
|
||||
dname_len = payload[0];
|
||||
if ((1 + dname_len) < length)
|
||||
{
|
||||
dname = (char*)&payload[1];
|
||||
sig_len = payload[1 + dname_len];
|
||||
sig = &payload[1 + dname_len + 1];
|
||||
if ((sig_len > 0) && ((1 + dname_len + 1 + sig_len) == length))
|
||||
{
|
||||
if ((ret = verify_contract_name_signature(dname_len, dname, sig_len, sig)))
|
||||
{
|
||||
ui_712_set_title("Contract", 8);
|
||||
ui_712_set_value(dname, dname_len);
|
||||
ui_712_redraw_generic_step();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool provide_field_name(const uint8_t *const payload, uint8_t length)
|
||||
{
|
||||
bool ret = false;
|
||||
uint8_t dname_len;
|
||||
const char *dname;
|
||||
uint8_t sig_len;
|
||||
const uint8_t *sig;
|
||||
bool name_provided = false;
|
||||
|
||||
if ((length > 0) && (path_get_root_type() == ROOT_MESSAGE))
|
||||
{
|
||||
dname_len = payload[0];
|
||||
if ((1 + dname_len) < length)
|
||||
{
|
||||
dname = (char*)&payload[1];
|
||||
sig_len = payload[1 + dname_len];
|
||||
sig = &payload[1 + dname_len + 1];
|
||||
if ((sig_len > 0) && ((1 + dname_len + 1 + sig_len) == length))
|
||||
{
|
||||
if ((ret = verify_field_name_signature(dname_len, dname, sig_len, sig)))
|
||||
{
|
||||
if (dname_len > 0) // don't substitute for an empty name
|
||||
{
|
||||
ui_712_set_title(dname, dname_len);
|
||||
name_provided = true;
|
||||
}
|
||||
ret = true;
|
||||
ui_712_flag_field(true, name_provided);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool handle_eip712_filtering(const uint8_t *const apdu_buf)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
switch (apdu_buf[OFFSET_P1])
|
||||
{
|
||||
case P1_ACTIVATE:
|
||||
ui_ctx->filtering_mode = EIP712_FILTERING_FULL;
|
||||
break;
|
||||
case P1_CONTRACT_NAME:
|
||||
if (ui_ctx->filtering_mode == EIP712_FILTERING_FULL)
|
||||
{
|
||||
ret = provide_contract_name(&apdu_buf[OFFSET_CDATA],
|
||||
apdu_buf[OFFSET_LC]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
break;
|
||||
case P1_FIELD_NAME:
|
||||
if (ui_ctx->filtering_mode == EIP712_FILTERING_FULL)
|
||||
{
|
||||
ret = provide_field_name(&apdu_buf[OFFSET_CDATA],
|
||||
apdu_buf[OFFSET_LC]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PRINTF("Unknown P1 0x%x for APDU 0x%x\n",
|
||||
apdu_buf[OFFSET_P1],
|
||||
apdu_buf[OFFSET_INS]);
|
||||
ret = false;
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
G_io_apdu_buffer[0] = 0x90;
|
||||
G_io_apdu_buffer[1] = 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
G_io_apdu_buffer[0] = 0x6A;
|
||||
G_io_apdu_buffer[1] = 0x80;
|
||||
}
|
||||
if ((apdu_buf[OFFSET_P1] != P1_CONTRACT_NAME) || (ret == false))
|
||||
{
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool handle_eip712_sign(const uint8_t *const apdu_buf)
|
||||
{
|
||||
if (parseBip32(&apdu_buf[OFFSET_CDATA],
|
||||
|
||||
@@ -397,6 +397,7 @@ bool path_set_root(const char *const struct_name, uint8_t name_length)
|
||||
#ifdef HAVE_EIP712_HALF_BLIND
|
||||
}
|
||||
#endif // HAVE_EIP712_HALF_BLIND
|
||||
ui_712_field_flags_reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -609,6 +610,7 @@ bool path_advance(void)
|
||||
}
|
||||
while (end_reached);
|
||||
path_update();
|
||||
ui_712_field_flags_reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "uint256.h" // tostring256 && tostring256_signed
|
||||
|
||||
|
||||
static t_ui_context *ui_ctx = NULL;
|
||||
t_ui_context *ui_ctx = NULL;
|
||||
|
||||
|
||||
static void ui_712_set_buf(const char *const src,
|
||||
@@ -144,7 +144,7 @@ void ui_712_message_hash(void)
|
||||
{
|
||||
const char *const title = "Message hash";
|
||||
|
||||
ui_712_set_title(title, strlen(titltitlee));
|
||||
ui_712_set_title(title, strlen(title));
|
||||
snprintf(strings.tmp.tmp,
|
||||
sizeof(strings.tmp.tmp),
|
||||
"0x%.*H",
|
||||
@@ -179,7 +179,10 @@ void ui_712_new_field(const void *const field_ptr, const uint8_t *const data,
|
||||
// Key
|
||||
if ((key = get_struct_field_keyname(field_ptr, &key_len)) != NULL)
|
||||
{
|
||||
ui_712_set_title(key, key_len);
|
||||
if (!(ui_ctx->field_flags & UI_712_FIELD_NAME_PROVIDED))
|
||||
{
|
||||
ui_712_set_title(key, key_len);
|
||||
}
|
||||
}
|
||||
|
||||
// Value
|
||||
@@ -305,6 +308,7 @@ bool ui_712_init(void)
|
||||
ui_ctx->shown = false;
|
||||
ui_ctx->end_reached = false;
|
||||
ui_ctx->pos = UI_712_POS_REVIEW;
|
||||
ui_ctx->filtering_mode = EIP712_FILTERING_BASIC;
|
||||
}
|
||||
return ui_ctx != NULL;
|
||||
}
|
||||
@@ -343,4 +347,21 @@ unsigned int ui_712_reject(const bagl_element_t *e)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ui_712_flag_field(bool show, bool name_provided)
|
||||
{
|
||||
if (show)
|
||||
{
|
||||
ui_ctx->field_flags |= UI_712_FIELD_SHOWN;
|
||||
}
|
||||
if (name_provided)
|
||||
{
|
||||
ui_ctx->field_flags |= UI_712_FIELD_NAME_PROVIDED;
|
||||
}
|
||||
}
|
||||
|
||||
void ui_712_field_flags_reset(void)
|
||||
{
|
||||
ui_ctx->field_flags = 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_EIP712_FULL_SUPPORT
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
#include <stdint.h>
|
||||
#include "ux.h"
|
||||
|
||||
#define UI_712_FIELD_SHOWN (1 << 0)
|
||||
#define UI_712_FIELD_NAME_PROVIDED (1 << 1)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EIP712_FILTERING_BASIC,
|
||||
EIP712_FILTERING_FULL
|
||||
} e_eip712_filtering_mode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UI_712_POS_REVIEW,
|
||||
@@ -17,8 +26,12 @@ typedef struct
|
||||
bool shown;
|
||||
bool end_reached;
|
||||
e_ui_position pos;
|
||||
uint8_t filtering_mode;
|
||||
uint8_t field_flags;
|
||||
} t_ui_context;
|
||||
|
||||
extern t_ui_context *ui_ctx;
|
||||
|
||||
bool ui_712_init(void);
|
||||
void ui_712_deinit(void);
|
||||
void ui_712_next_field(void);
|
||||
@@ -33,6 +46,8 @@ void ui_712_set_value(const char *const str, uint8_t length);
|
||||
void ui_712_message_hash(void);
|
||||
#endif // HAVE_EIP712_HALF_BLIND
|
||||
void ui_712_redraw_generic_step(void);
|
||||
void ui_712_flag_field(bool show, bool name_provided);
|
||||
void ui_712_field_flags_reset(void);
|
||||
|
||||
#endif // HAVE_EIP712_FULL_SUPPORT
|
||||
|
||||
|
||||
Reference in New Issue
Block a user