Skip to content

Commit

Permalink
Merge pull request #63 from trilitech/palmer@functori@document-the-code
Browse files Browse the repository at this point in the history
Document the code - Part 1
  • Loading branch information
ajinkyaraj-23 authored Mar 12, 2024
2 parents 7df52b7 + 213bba6 commit 68ac5ef
Show file tree
Hide file tree
Showing 33 changed files with 895 additions and 286 deletions.
28 changes: 1 addition & 27 deletions src/apdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ size_t handle_apdu_git(uint8_t __attribute__((unused)) instruction,
return finalize_successful_send(tx);
}

#define CLA 0x80
#define CLA 0x80 /// The only APDU class that will be used

__attribute__((noreturn)) void main_loop(apdu_handler const* const handlers,
size_t const handlers_size) {
Expand Down Expand Up @@ -131,29 +131,3 @@ __attribute__((noreturn)) void main_loop(apdu_handler const* const handlers,
END_TRY;
}
}

// I have no idea what this function does, but it is called by the OS
unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
switch (channel & ~(IO_FLAGS)) {
case CHANNEL_KEYBOARD:
break;

// multiplexed io exchange over a SPI channel and TLV encapsulated protocol
case CHANNEL_SPI:
if (tx_len) {
io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);

if (channel & IO_RESET_AFTER_REPLIED) {
reset();
}
return 0; // nothing received from the master so far (it's a tx
// transaction)
} else {
return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
}

default:
THROW(INVALID_PARAMETER);
}
return 0;
}
92 changes: 79 additions & 13 deletions src/apdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,27 @@
#include <stdbool.h>
#include <stdint.h>

#define OFFSET_CLA 0
#define OFFSET_INS 1 // instruction code
#define OFFSET_P1 2 // user-defined 1-byte parameter
#define OFFSET_CURVE 3
#define OFFSET_LC 4 // length of CDATA
#define OFFSET_CDATA 5 // payload

// Instruction codes
/**
* @brief Offset for the different items in an APDU
*
*/
#define OFFSET_CLA 0 /// APDU class
#define OFFSET_INS 1 /// instruction code
#define OFFSET_P1 2 /// packet index
#define OFFSET_CURVE 3 /// key curve: derivation_type_t
#define OFFSET_LC 4 /// length of payload
#define OFFSET_CDATA 5 /// payload

/**
* @brief Codes of handled instructions
*
*/
#define INS_VERSION 0x00
#define INS_AUTHORIZE_BAKING 0x01
#define INS_GET_PUBLIC_KEY 0x02
#define INS_PROMPT_PUBLIC_KEY 0x03
#define INS_SIGN 0x04
#define INS_SIGN_UNSAFE 0x05 // Data that is already hashed.
#define INS_SIGN_UNSAFE 0x05
#define INS_RESET 0x06
#define INS_QUERY_AUTH_KEY 0x07
#define INS_QUERY_MAIN_HWM 0x08
Expand All @@ -56,20 +63,41 @@
#define INS_HMAC 0x0E
#define INS_SIGN_WITH_HASH 0x0F

__attribute__((noreturn)) void main_loop(apdu_handler const* const handlers,
size_t const handlers_size);

/**
* @brief Loops indefinitely while handling the incoming apdus
*
* @param handlers: list of apdu handler
* @param handlers_size: updated offset of the apdu response
*/
void main_loop(apdu_handler const* const handlers, size_t const handlers_size)
__attribute__((noreturn));

/**
* @brief Tags as successful apdu response
*
* @param tx: current offset of the apdu response
* @return size_t: updated offset of the apdu response
*/
static inline size_t finalize_successful_send(size_t tx) {
G_io_apdu_buffer[tx++] = 0x90;
G_io_apdu_buffer[tx++] = 0x00;
return tx;
}

// Send back response; do not restart the event loop
/**
* @brief Sends the apdu response asynchronously
*
* @param tx: current offset of the apdu response
*/
static inline void delayed_send(size_t tx) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
}

/**
* @brief Sends asynchronously a reject exception
*
* @return true
*/
static inline bool delay_reject(void) {
size_t tx = 0;
G_io_apdu_buffer[tx++] = EXC_REJECT >> 8;
Expand All @@ -78,8 +106,46 @@ static inline bool delay_reject(void) {
return true;
}

/**
* @brief Provides the public key in the apdu response
*
* Expects validated pin
*
* @param io_buffer: apdu response buffer
* @param pubkey: public key
* @return size_t: offset of the apdu response
*/
size_t provide_pubkey(uint8_t* const io_buffer, cx_ecfp_public_key_t const* const pubkey);

/**
* @brief Handles unknown instructions
*
* Raises an invalid instruction exception
*
* @param instruction: apdu instruction
* @param flags: io flags
* @return size_t: offset of the apdu response
*/
size_t handle_apdu_error(uint8_t instruction, volatile uint32_t* flags);

/**
* @brief Handles VERSION instruction
*
* Fills apdu response with the app version
*
* @param instruction: apdu instruction
* @param flags: io flags
* @return size_t: offset of the apdu response
*/
size_t handle_apdu_version(uint8_t instruction, volatile uint32_t* flags);

/**
* @brief Handles GIT instruction
*
* Fills apdu response with the app commit
*
* @param instruction: apdu instruction
* @param flags: io flags
* @return size_t: offset of the apdu response
*/
size_t handle_apdu_git(uint8_t instruction, volatile uint32_t* flags);
29 changes: 25 additions & 4 deletions src/apdu_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,26 @@

#define G global.apdu.u.hmac

/**
* @brief Generate the hmac of a message
*
* The hmac-key is the signature of a fixed message signed with a given key
*
* @param out: result output
* @param out_size: output size
* @param state: hmac state
* @param in: input message
* @param in_size: input size
* @param bip32_path: key path
* @param derivation_type: key curve
* @return size_t: size of the hmac
*/
static inline size_t hmac(uint8_t *const out,
size_t const out_size,
apdu_hmac_state_t *const state,
uint8_t const *const in,
size_t const in_size,
bip32_path_t bip32_path,
derivation_type_t derivation_type) {
check_null(out);
check_null(state);
Expand All @@ -51,7 +66,7 @@ static inline size_t hmac(uint8_t *const out,

BEGIN_TRY {
TRY {
generate_key_pair(&key_pair, derivation_type, &global.path_with_curve.bip32_path);
generate_key_pair(&key_pair, derivation_type, &bip32_path);
signed_hmac_key_size = sign(state->signed_hmac_key,
sizeof(state->signed_hmac_key),
derivation_type,
Expand Down Expand Up @@ -98,14 +113,20 @@ size_t handle_apdu_hmac(__attribute__((unused)) uint8_t instruction,

derivation_type_t derivation_type = parse_derivation_type(G_io_apdu_buffer[OFFSET_CURVE]);

bip32_path_t bip32_path = {0};
size_t consumed = 0;
consumed += read_bip32_path(&global.path_with_curve.bip32_path, buff, buff_size);
consumed += read_bip32_path(&bip32_path, buff, buff_size);

uint8_t const *const data_to_hmac = &buff[consumed];
size_t const data_to_hmac_size = buff_size - consumed;

size_t const hmac_size =
hmac(G.hmac, sizeof(G.hmac), &G, data_to_hmac, data_to_hmac_size, derivation_type);
size_t const hmac_size = hmac(G.hmac,
sizeof(G.hmac),
&G,
data_to_hmac,
data_to_hmac_size,
bip32_path,
derivation_type);

size_t tx = 0;
memcpy(G_io_apdu_buffer, G.hmac, hmac_size);
Expand Down
9 changes: 9 additions & 0 deletions src/apdu_hmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,13 @@

#include "apdu.h"

/**
* @brief Handles HMAC instruction
*
* Fills apdu response with the hmac
*
* @param instruction: apdu instruction
* @param flags: io flags
* @return size_t: offset of the apdu response
*/
size_t handle_apdu_hmac(uint8_t instruction, volatile uint32_t* flags);
24 changes: 14 additions & 10 deletions src/apdu_pubkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@
#include "protocol.h"
#include "to_string.h"
#include "ui.h"
#include "ui_pubkey.h"
#include "baking_auth.h"

#include <string.h>

/**
* @brief Sends apdu response with the public key
*
* @return true
*/
static bool pubkey_ok(void) {
cx_ecfp_public_key_t public_key = {0};
generate_public_key(&public_key,
Expand All @@ -41,21 +47,19 @@ static bool pubkey_ok(void) {
return true;
}

/**
* @brief Authorizes the public key
*
* Sends apdu response with the public key
*
* @return true
*/
static bool baking_ok(void) {
authorize_baking(global.path_with_curve.derivation_type, &global.path_with_curve.bip32_path);
pubkey_ok();
return true;
}

char const *const *get_baking_prompts() {
static const char *const baking_prompts[] = {
PROMPT("Authorize Baking"),
PROMPT("Public Key Hash"),
NULL,
};
return baking_prompts;
}

size_t handle_apdu_get_public_key(uint8_t instruction, volatile uint32_t *flags) {
uint8_t *dataBuffer = G_io_apdu_buffer + OFFSET_CDATA;

Expand Down Expand Up @@ -95,7 +99,7 @@ size_t handle_apdu_get_public_key(uint8_t instruction, volatile uint32_t *flags)
cb = pubkey_ok;
bake = false;
}
prompt_address(bake, cb, delay_reject);
prompt_pubkey(bake, cb, delay_reject);
*flags = IO_ASYNCH_REPLY;
return 0;
}
Expand Down
9 changes: 7 additions & 2 deletions src/apdu_pubkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@

#include "apdu.h"

/**
* @brief Handles AUTHORIZE_BAKING, GET_PUBLIC_KEY and PROMPT_PUBLIC_KEY instructions
*
* @param instruction: apdu instruction
* @param flags: io flags
* @return size_t: offset of the apdu response
*/
size_t handle_apdu_get_public_key(uint8_t instruction, volatile uint32_t* flags);

void prompt_address(bool baking, ui_callback_t ok_cb, ui_callback_t cxl_cb);
57 changes: 9 additions & 48 deletions src/apdu_baking.c → src/apdu_query.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Tezos Ledger application - Baking APDU instruction handling
/* Tezos Ledger application - Query APDU instruction handling
Copyright 2024 TriliTech <[email protected]>
Copyright 2024 Functori <[email protected]>
Expand All @@ -20,7 +20,7 @@
*/

#include "apdu_baking.h"
#include "apdu_query.h"

#include "apdu.h"
#include "baking_auth.h"
Expand All @@ -32,39 +32,13 @@

#include <string.h>

#define G global.apdu.u.baking

size_t handle_apdu_reset(__attribute__((unused)) uint8_t instruction, volatile uint32_t* flags) {
uint8_t* dataBuffer = G_io_apdu_buffer + OFFSET_CDATA;
uint32_t dataLength = G_io_apdu_buffer[OFFSET_LC];
if (dataLength != sizeof(level_t)) {
THROW(EXC_WRONG_LENGTH_FOR_INS);
}
level_t const lvl = READ_UNALIGNED_BIG_ENDIAN(level_t, dataBuffer);
if (!is_valid_level(lvl)) {
THROW(EXC_PARSE_ERROR);
}

G.reset_level = lvl;
ui_baking_reset(flags);
return 0;
}

bool reset_ok(void) {
UPDATE_NVRAM(ram, {
ram->hwm.main.highest_level = G.reset_level;
ram->hwm.main.highest_round = 0;
ram->hwm.main.had_endorsement = false;
ram->hwm.test.highest_level = G.reset_level;
ram->hwm.test.highest_round = 0;
ram->hwm.test.had_endorsement = false;
});

// Send back the response, do not restart the event loop
delayed_send(finalize_successful_send(0));
return true;
}

/**
* @brief Inserts big endian word in the apdu response
*
* @param tx: current offset of the apdu response
* @param word: big endian word
* @return size_t: updated offset of the apdu response
*/
size_t send_word_big_endian(size_t tx, uint32_t word) {
char word_bytes[sizeof(word)];

Expand Down Expand Up @@ -133,16 +107,3 @@ size_t handle_apdu_query_auth_key_with_curve(__attribute__((unused)) uint8_t ins

return finalize_successful_send(tx);
}

size_t handle_apdu_deauthorize(__attribute__((unused)) uint8_t instruction,
__attribute__((unused)) volatile uint32_t* flags) {
if (G_io_apdu_buffer[OFFSET_P1] != 0) {
THROW(EXC_WRONG_PARAM);
}
if (G_io_apdu_buffer[OFFSET_LC] != 0) {
THROW(EXC_PARSE_ERROR);
}
UPDATE_NVRAM(ram, { memset(&ram->baking_key, 0, sizeof(ram->baking_key)); });

return finalize_successful_send(0);
}
Loading

0 comments on commit 68ac5ef

Please sign in to comment.