EIP712 STRUCT FIELD DEF now checks the APDU payload bounds

This commit is contained in:
Alexandre Paillier
2022-07-13 18:33:29 +02:00
parent 0cc75edf69
commit b4fe42cd78
3 changed files with 142 additions and 40 deletions

View File

@@ -61,7 +61,7 @@ bool handle_eip712_struct_def(const uint8_t *const apdu_buf)
ret = set_struct_name(apdu_buf[OFFSET_LC], &apdu_buf[OFFSET_CDATA]);
break;
case P2_FIELD:
ret = set_struct_field(apdu_buf);
ret = set_struct_field(apdu_buf[OFFSET_LC], &apdu_buf[OFFSET_CDATA]);
break;
default:
PRINTF("Unknown P2 0x%x for APDU 0x%x\n",

View File

@@ -14,7 +14,7 @@ static s_typed_data *typed_data = NULL;
/**
* Initialize the typed data context
*
* @return whether the memory allocation was successful or not
* @return whether the memory allocation was successful
*/
bool typed_data_init(void)
{
@@ -185,7 +185,7 @@ static inline typedesc_t get_struct_field_typedesc(const uint8_t *const field_pt
* Check whether a struct field is an array
*
* @param[in] field_ptr struct field pointer
* @return bool whether it is the case or not
* @return bool whether it is the case
*/
bool struct_field_is_array(const uint8_t *const field_ptr)
{
@@ -196,7 +196,7 @@ bool struct_field_is_array(const uint8_t *const field_ptr)
* Check whether a struct field has a type size associated to it
*
* @param[in] field_ptr struct field pointer
* @return bool whether it is the case or not
* @return bool whether it is the case
*/
bool struct_field_has_typesize(const uint8_t *const field_ptr)
{
@@ -508,7 +508,7 @@ const uint8_t *get_structn(const char *const name,
*
* @param[in] length name length
* @param[in] name name
* @return whether it was successful or not
* @return whether it was successful
*/
bool set_struct_name(uint8_t length, const uint8_t *const name)
{
@@ -549,20 +549,54 @@ bool set_struct_name(uint8_t length, const uint8_t *const name)
return true;
}
/**
* Set struct field TypeDesc
*
* @param[in] data the field data
* @param[in] data_idx the data index
* @return pointer to the TypeDesc in memory
*/
static const typedesc_t *set_struct_field_typedesc(const uint8_t *const data,
uint8_t *data_idx,
uint8_t length)
{
typedesc_t *typedesc_ptr;
// copy TypeDesc
if ((*data_idx + sizeof(*typedesc_ptr)) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((typedesc_ptr = mem_alloc(sizeof(uint8_t))) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
return NULL;
}
*typedesc_ptr = data[(*data_idx)++];
return typedesc_ptr;
}
/**
* Set struct field custom typename
*
* @param[in] data the field data
* @param[in] data_idx the data index
* @return whether it was successful or not
* @return whether it was successful
*/
static bool set_struct_field_custom_typename(const uint8_t *const data,
uint8_t *data_idx)
uint8_t *data_idx,
uint8_t length)
{
uint8_t *typename_len_ptr;
char *typename;
// copy custom struct name length
if ((*data_idx + sizeof(*typename_len_ptr)) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((typename_len_ptr = mem_alloc(sizeof(uint8_t))) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
@@ -571,6 +605,11 @@ static bool set_struct_field_custom_typename(const uint8_t *const data,
*typename_len_ptr = data[(*data_idx)++];
// copy name
if ((*data_idx + *typename_len_ptr) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((typename = mem_alloc(sizeof(char) * *typename_len_ptr)) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
@@ -586,14 +625,21 @@ static bool set_struct_field_custom_typename(const uint8_t *const data,
*
* @param[in] data the field data
* @param[in] data_idx the data index
* @return whether it was successful or not
* @return whether it was successful
*/
static bool set_struct_field_array(const uint8_t *const data, uint8_t *data_idx)
static bool set_struct_field_array(const uint8_t *const data,
uint8_t *data_idx,
uint8_t length)
{
uint8_t *array_levels_count;
e_array_type *array_level;
uint8_t *array_level_size;
if ((*data_idx + sizeof(*array_levels_count)) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((array_levels_count = mem_alloc(sizeof(uint8_t))) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
@@ -602,6 +648,11 @@ static bool set_struct_field_array(const uint8_t *const data, uint8_t *data_idx)
*array_levels_count = data[(*data_idx)++];
for (int idx = 0; idx < *array_levels_count; ++idx)
{
if ((*data_idx + sizeof(*array_level)) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((array_level = mem_alloc(sizeof(uint8_t))) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
@@ -613,6 +664,11 @@ static bool set_struct_field_array(const uint8_t *const data, uint8_t *data_idx)
case ARRAY_DYNAMIC: // nothing to do
break;
case ARRAY_FIXED_SIZE:
if ((*data_idx + sizeof(*array_level_size)) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((array_level_size = mem_alloc(sizeof(uint8_t))) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
@@ -634,36 +690,90 @@ static bool set_struct_field_array(const uint8_t *const data, uint8_t *data_idx)
*
* @param[in] data the field data
* @param[in,out] data_idx the data index
* @return whether it was successful or not
* @return whether it was successful
*/
static bool set_struct_field_typesize(const uint8_t *const data, uint8_t *data_idx)
static bool set_struct_field_typesize(const uint8_t *const data,
uint8_t *data_idx,
uint8_t length)
{
uint8_t *type_size_ptr;
uint8_t *typesize_ptr;
// copy TypeSize
if ((type_size_ptr = mem_alloc(sizeof(uint8_t))) == NULL)
if ((*data_idx + sizeof(*typesize_ptr)) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((typesize_ptr = mem_alloc(sizeof(uint8_t))) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
return false;
}
*type_size_ptr = data[(*data_idx)++];
*typesize_ptr = data[(*data_idx)++];
return true;
}
/**
* Set struct field's key name
*
* @param[in] data the field data
* @param[in,out] data_idx the data index
* @return whether it was successful
*/
static bool set_struct_field_keyname(const uint8_t *const data,
uint8_t *data_idx,
uint8_t length)
{
uint8_t *keyname_len_ptr;
char *keyname_ptr;
// copy length
if ((*data_idx + sizeof(*keyname_len_ptr)) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((keyname_len_ptr = mem_alloc(sizeof(uint8_t))) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
return false;
}
*keyname_len_ptr = data[(*data_idx)++];
// copy name
if ((*data_idx + *keyname_len_ptr) > length) // check buffer bound
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
if ((keyname_ptr = mem_alloc(sizeof(char) * *keyname_len_ptr)) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
return false;
}
memmove(keyname_ptr, &data[*data_idx], *keyname_len_ptr);
*data_idx += *keyname_len_ptr;
return true;
}
/**
* Set struct field
*
* @param[in] length data length
* @param[in] data the field data
* @return whether it was successful or not
* @return whether it was successful
*/
bool set_struct_field(const uint8_t *const data)
bool set_struct_field(uint8_t length, const uint8_t *const data)
{
uint8_t data_idx = OFFSET_CDATA;
uint8_t *type_desc_ptr;
uint8_t *fieldname_len_ptr;
char *fieldname_ptr;
const typedesc_t *typedesc_ptr;
uint8_t data_idx = 0;
if ((data == NULL) || (typed_data == NULL))
if ((data == NULL) || (length == 0))
{
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
else if (typed_data == NULL)
{
apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED;
return false;
@@ -671,52 +781,44 @@ bool set_struct_field(const uint8_t *const data)
// increment number of struct fields
*(typed_data->current_struct_fields_array) += 1;
// copy TypeDesc
if ((type_desc_ptr = mem_alloc(sizeof(uint8_t))) == NULL)
if ((typedesc_ptr = set_struct_field_typedesc(data, &data_idx, length)) == NULL)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
return false;
}
*type_desc_ptr = data[data_idx++];
// check TypeSize flag in TypeDesc
if (*type_desc_ptr & TYPESIZE_MASK)
if (*typedesc_ptr & TYPESIZE_MASK)
{
if (set_struct_field_typesize(data, &data_idx) == false)
if (set_struct_field_typesize(data, &data_idx, length) == false)
{
return false;
}
}
else if ((*type_desc_ptr & TYPE_MASK) == TYPE_CUSTOM)
else if ((*typedesc_ptr & TYPE_MASK) == TYPE_CUSTOM)
{
if (set_struct_field_custom_typename(data, &data_idx) == false)
if (set_struct_field_custom_typename(data, &data_idx, length) == false)
{
return false;
}
}
if (*type_desc_ptr & ARRAY_MASK)
if (*typedesc_ptr & ARRAY_MASK)
{
if (set_struct_field_array(data, &data_idx) == false)
if (set_struct_field_array(data, &data_idx, length) == false)
{
return false;
}
}
// copy length
if ((fieldname_len_ptr = mem_alloc(sizeof(uint8_t))) == NULL)
if (set_struct_field_keyname(data, &data_idx, length) == false)
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
return false;
}
*fieldname_len_ptr = data[data_idx++];
// copy name
if ((fieldname_ptr = mem_alloc(sizeof(char) * *fieldname_len_ptr)) == NULL)
if (data_idx != length) // check that there is no more
{
apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
return false;
}
memmove(fieldname_ptr, &data[data_idx], *fieldname_len_ptr);
return true;
}

View File

@@ -70,7 +70,7 @@ const uint8_t *get_structs_array(uint8_t *const length);
const uint8_t *get_structn(const char *const name_ptr,
const uint8_t name_length);
bool set_struct_name(uint8_t length, const uint8_t *const name);
bool set_struct_field(const uint8_t *const data);
bool set_struct_field(uint8_t length, const uint8_t *const data);
bool typed_data_init(void);
void typed_data_deinit(void);