Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document the code - Part 2 #68

Merged
merged 15 commits into from
Mar 13, 2024
Merged
8 changes: 4 additions & 4 deletions .doxygen/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ TIMESTAMP = NO
# normally produced when WARNINGS is set to YES.
# The default value is: NO.

EXTRACT_ALL = YES
EXTRACT_ALL = NO

# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
Expand Down Expand Up @@ -877,15 +877,15 @@ WARN_IF_INCOMPLETE_DOC = YES
# WARN_IF_INCOMPLETE_DOC
# The default value is: NO.

WARN_NO_PARAMDOC = NO
WARN_NO_PARAMDOC = YES

# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
# undocumented enumeration values. If set to NO, doxygen will accept
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: NO.

WARN_IF_UNDOC_ENUM_VAL = NO
WARN_IF_UNDOC_ENUM_VAL = YES

# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
Expand All @@ -901,7 +901,7 @@ WARN_IF_UNDOC_ENUM_VAL = NO
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
# The default value is: NO.

WARN_AS_ERROR = NO
WARN_AS_ERROR = YES

# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
Expand Down
3 changes: 3 additions & 0 deletions src/apdu_setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ size_t handle_apdu_deauthorize(__attribute__((unused)) uint8_t instruction,
THROW(EXC_PARSE_ERROR);
}
UPDATE_NVRAM(ram, { memset(&ram->baking_key, 0, sizeof(ram->baking_key)); });
#ifdef HAVE_BAGL
update_baking_idle_screens();
#endif // HAVE_BAGL

return finalize_successful_send(0);
}
109 changes: 81 additions & 28 deletions src/baking_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ void authorize_baking(derivation_type_t const derivation_type,
});
}

/**
* @brief Checks if a baking info pass all checks
*
* See `doc/signing.md#checks`
*
* @param baking_info: baking info
* @return bool: return true if it has passed checks
*/
static bool is_level_authorized(parsed_baking_data_t const *const baking_info) {
check_null(baking_info);
if (!is_valid_level(baking_info->level)) {
Expand Down Expand Up @@ -104,6 +112,13 @@ static bool is_level_authorized(parsed_baking_data_t const *const baking_info) {
}
}

/**
* @brief Checks if a key pass the checks
*
* @param derivation_type: curve of the key
* @param bip32_path: bip32 path of the key
* @return bool: return true if it has passed checks
*/
bool is_path_authorized(derivation_type_t const derivation_type,
bip32_path_t const *const bip32_path) {
check_null(bip32_path);
Expand All @@ -124,43 +139,46 @@ void guard_baking_authorized(parsed_baking_data_t const *const baking_info,
}
}

/**
* @brief Raw representation of block
*
* All information of the block are not parsed here.
*
* Except the fitness placed just after fitness size, the rest
* of the block content is not important for our checks
*
* Fitness =
* - tag_size(4) + tag(1) +
* - level_size(4) + level(4) +
* - locked_round_size(4) + locked_round(0|4) +
* - predecessor_round_size(4) + predecessor_round(4) +
* - current_round_size(4) + current_round(4)
*
*/
struct block_wire {
uint8_t magic_byte;
uint32_t chain_id;
uint32_t level;
uint8_t proto;
uint8_t predecessor[32];
uint64_t timestamp;
uint8_t validation_pass;
uint8_t operation_hash[32];
uint32_t fitness_size;
uint8_t magic_byte; ///< magic bytes, should be 0x11
uint32_t chain_id; ///< chain id of the block
uint32_t level; ///< height of the block, from the genesis block
uint8_t proto; ///< protocol number
uint8_t predecessor[32]; ///< hash of the preceding block
uint64_t timestamp; ///< timestamp at which the block have been created
uint8_t validation_pass; ///< number of validation passes
uint8_t operation_hash[32]; ///< hash of the operations
uint32_t fitness_size; ///< size of the fitness
// ... beyond this we don't care
} __attribute__((packed));

struct consensus_op_wire {
uint8_t magic_byte;
uint32_t chain_id;
uint8_t branch[32];
uint8_t tag;
uint16_t slot;
uint32_t level;
uint32_t round;
uint8_t block_payload_hash[32];
} __attribute__((packed));

/**
* Fitness =
* - tag_size(4) + tag(1) +
* - level_size(4) + level(4) +
* - locked_round_size(4) + locked_round(0|4) +
* - predecessor_round_size(4) + predecessor_round(4) +
* - current_round_size(4) + current_round(4)
*/
#define MINIMUM_FITNESS_SIZE 33 // When 'locked_round' == none
#define MAXIMUM_FITNESS_SIZE 37 // When 'locked_round' != none

#define TENDERBAKE_PROTO_FITNESS_VERSION 2

/**
* @brief Get the protocol version from fitness
*
* @param fitness: fitness
* @return uint8_t: protocol version result
*/
uint8_t get_proto_version(void const *const fitness) {
// Each field is preceded by its size (uint32_t).
// That's why we need to look at `sizeof(uint32_t)` bytes after
Expand All @@ -171,6 +189,14 @@ uint8_t get_proto_version(void const *const fitness) {
return READ_UNALIGNED_BIG_ENDIAN(uint8_t, fitness + sizeof(uint32_t));
}

/**
* @brief Parse a block
*
* @param out: baking data output
* @param data: input
* @param length: input length
* @return bool: returns false if it is invalid
*/
bool parse_block(parsed_baking_data_t *const out, void const *const data, size_t const length) {
if (length < sizeof(struct block_wire) + MINIMUM_FITNESS_SIZE) {
return false;
Expand All @@ -196,6 +222,33 @@ bool parse_block(parsed_baking_data_t *const out, void const *const data, size_t
return true;
}

/**
* @brief Raw representation of a consensus operation
*
* - Pre-attestation , tag: 20
* - Attestation , tag: 21
* - Attestation + DAL, tag: 23
*
*/
struct consensus_op_wire {
uint8_t magic_byte; ///< magic bytes, should be 0x12, or 0x13
uint32_t chain_id; ///< chain id of the block
uint8_t branch[32]; ///< block branch
uint8_t tag; ///< operation tag
uint16_t slot; ///< first slot of the baker
uint32_t level; ///< level of the related block
uint32_t round; ///< round of the related block
uint8_t block_payload_hash[32]; ///< hash of the related block
} __attribute__((packed));

/**
* @brief Parse a consensus operation
*
* @param out: baking data output
* @param data: input
* @param length: input length
* @return bool: returns false if it is invalid
*/
bool parse_consensus_operation(parsed_baking_data_t *const out,
void const *const data,
size_t const length) {
Expand Down
39 changes: 35 additions & 4 deletions src/baking_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,47 @@
#include <stdbool.h>
#include <stdint.h>

/**
* @brief Authorizes a key
*
* @param derivation_type: curve of the key
* @param bip32_path: bip32 path of the key
*/
void authorize_baking(derivation_type_t const derivation_type,
bip32_path_t const *const bip32_path);
void guard_baking_authorized(parsed_baking_data_t const *const baking_data,

/**
* @brief Guards baking info and key pass required checks
*
* @param baking_info: baking info to check
* @param key: key to check
*/
void guard_baking_authorized(parsed_baking_data_t const *const baking_info,
bip32_path_with_curve_t const *const key);
bool is_path_authorized(derivation_type_t const derivation_type,
bip32_path_t const *const bip32_path);

/**
* @brief Checks if a level is valid
*
* @param level: level
* @return bool: if the level is valid
*/
bool is_valid_level(level_t level);

/**
* @brief Stores baking info into the NVRAM
*
* @param in: baking info
*/
void write_high_water_mark(parsed_baking_data_t const *const in);

// Return false if it is invalid
/**
* @brief Parses a baking data
*
* @param out: baking data output
* @param data: input
* @param length: input length
* @return bool: returns false if it is invalid
*/
bool parse_baking_data(parsed_baking_data_t *const out,
void const *const data,
size_t const length);
17 changes: 13 additions & 4 deletions src/exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@
// Throw this to indicate prompting
#define ASYNC_EXCEPTION 0x2000

// Standard APDU error codes:
// https://www.eftlab.co.uk/index.php/site-map/knowledge-base/118-apdu-response-list

/**
* @brief Standard APDU error codes
*
* https://www.eftlab.co.uk/index.php/site-map/knowledge-base/118-apdu-response-list
*
*/
#define EXC_WRONG_PARAM 0x6B00
#define EXC_WRONG_LENGTH 0x6C00
#define EXC_INVALID_INS 0x6D00
Expand All @@ -41,7 +44,13 @@
#define EXC_CLASS 0x6E00
#define EXC_MEMORY_ERROR 0x9200

// Crashes can be harder to debug than exceptions and latency isn't a big concern
/**
* @brief Checks if a pointer is NULL
*
* Crashes can be harder to debug than exceptions and latency isn't a big concern
*
* @param ptr: pointer
*/
static inline void check_null(void volatile const *const ptr) {
if (ptr == NULL) {
THROW(EXC_MEMORY_ERROR);
Expand Down
Loading
Loading