Skip to content

Commit

Permalink
Merge pull request #444 from Cypherock/feat/save-wallet-nonce-on-crea…
Browse files Browse the repository at this point in the history
…tion/PRF-6203

feat(core): Handle wallet collision while creation
  • Loading branch information
amanCypherock authored Dec 27, 2023
2 parents f88f382 + e80e581 commit 1eb7daf
Show file tree
Hide file tree
Showing 35 changed files with 454 additions and 117 deletions.
13 changes: 12 additions & 1 deletion common/Firewall/sec_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
#include "utils.h"

#define SEC_FLASH_STRUCT_TLV_SIZE \
(6 + 3 + (MAX_WALLETS_ALLOWED * (9 + sizeof(Wallet_Share_Data))) + 3 + \
(6 + 3 + (MAX_WALLETS_ALLOWED * (12 + sizeof(Wallet_Share_Data))) + 3 + \
(MAX_KEYSTORE_ENTRY * ((4 * 3) + sizeof(Card_Keystore))))

#define FLASH_WRITE_PERM_STRUCTURE_SIZE sizeof(Flash_Perm_Struct) / 4
Expand All @@ -85,6 +85,7 @@ typedef enum Sec_Flash_tlv_tags {
TAG_SEC_FLASH_WALLET_SHARE_STRUCT = 0x11,
TAG_SEC_FLASH_WALLET_ID = 0x12,
TAG_SEC_FLASH_WALLET_SHARE = 0x13,
TAG_SEC_FLASH_WALLET_NONCE = 0x14,

TAG_SEC_FLASH_KEYSTORE = 0x30,
TAG_SEC_FLASH_KEYSTORE_USED = 0x31,
Expand Down Expand Up @@ -551,6 +552,11 @@ static void serialize_sec_fs_wallet(uint8_t *array,
TAG_SEC_FLASH_WALLET_SHARE,
BLOCK_SIZE,
sec_fs->wallet_share_data[wallet_index].wallet_share);
fill_flash_tlv(array,
starting_index,
TAG_SEC_FLASH_WALLET_NONCE,
PADDED_NONCE_SIZE,
sec_fs->wallet_share_data[wallet_index].wallet_nonce);

array[len_index] = (*starting_index) - len_index - 2;
array[len_index + 1] = ((*starting_index) - len_index - 2) >> 8;
Expand Down Expand Up @@ -710,6 +716,11 @@ static void deserialize_sec_fs_wallet(Wallet_Share_Data *wallet_share_data,
break;
}

case TAG_SEC_FLASH_WALLET_NONCE: {
memcpy(wallet_share_data->wallet_nonce, tlv + index + 2, size);
break;
}

case TAG_SEC_FLASH_WALLET_ID: {
memcpy(wallet_share_data->wallet_id, tlv + index + 2, size);
break;
Expand Down
2 changes: 2 additions & 0 deletions common/Firewall/sec_flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ typedef struct Wallet_share {
uint8_t wallet_id[WALLET_ID_SIZE]; ///< Wallet ID derived from seed
uint8_t
wallet_share[BLOCK_SIZE]; ///< Device's (5th) share derived from seed
uint8_t wallet_nonce[PADDED_NONCE_SIZE]; ///< Wallet's nonce including IV
///< and version data
} Wallet_Share_Data;
#pragma pack(pop)

Expand Down
6 changes: 4 additions & 2 deletions common/coin_support/wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ bool encrypt_shares() {
&ctx, wallet_shamir_data.mnemonic_shares[i], share, BLOCK_SIZE);
chacha20poly1305_finish(
&ctx,
(uint8_t *)(wallet_shamir_data.share_encryption_data[i] + NONCE_SIZE));
(uint8_t *)(wallet_shamir_data.share_encryption_data[i] +
PADDED_NONCE_SIZE));
memcpy(wallet_shamir_data.mnemonic_shares[i], share, BLOCK_SIZE);
}

Expand All @@ -134,7 +135,8 @@ bool decrypt_shares() {
&ctx, wallet_shamir_data.mnemonic_shares[i], share, BLOCK_SIZE);
chacha20poly1305_finish(
&ctx,
(uint8_t *)(wallet_shamir_data.share_encryption_data[i] + NONCE_SIZE));
(uint8_t *)(wallet_shamir_data.share_encryption_data[i] +
PADDED_NONCE_SIZE));
// TODO: Add mac comparison for decryption verification
memcpy(wallet_shamir_data.mnemonic_shares[i], share, BLOCK_SIZE);
}
Expand Down
9 changes: 6 additions & 3 deletions common/coin_support/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
CARD_VERSION_GIT_REV_SIZE)

#define BLOCK_SIZE 32
#define NONCE_SIZE 16
#define NONCE_SIZE 12
#define PADDED_NONCE_SIZE \
NONCE_SIZE + 4 // 3 bytes as RFU and LSB as version byte
#define HASH_SIZE 32
#define WALLET_MAC_SIZE 16
#define PIN_SHARE_SIZE 80
#define CHECKSUM_SIZE 4
Expand Down Expand Up @@ -115,7 +118,7 @@ typedef struct Wallet {
uint8_t wallet_info;
uint8_t password_double_hash[BLOCK_SIZE];

uint8_t wallet_share_with_mac_and_nonce[BLOCK_SIZE + NONCE_SIZE +
uint8_t wallet_share_with_mac_and_nonce[BLOCK_SIZE + PADDED_NONCE_SIZE +
WALLET_MAC_SIZE];
uint8_t arbitrary_data_share[512];

Expand Down Expand Up @@ -156,7 +159,7 @@ typedef struct Wallet_shamir_data {
};
uint8_t share_x_coords[TOTAL_NUMBER_OF_SHARES];
uint8_t share_encryption_data[TOTAL_NUMBER_OF_SHARES]
[NONCE_SIZE + WALLET_MAC_SIZE];
[PADDED_NONCE_SIZE + WALLET_MAC_SIZE];
} Wallet_shamir_data;
#pragma pack(pop)

Expand Down
2 changes: 1 addition & 1 deletion common/interfaces/card_interface/apdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ uint16_t create_apdu_add_wallet(const struct Wallet *wallet, uint8_t apdu[]) {
fill_tlv(apdu,
&index,
INS_WALLET_SHARE,
BLOCK_SIZE + NONCE_SIZE + WALLET_MAC_SIZE,
BLOCK_SIZE + PADDED_NONCE_SIZE + WALLET_MAC_SIZE,
wallet);
fill_tlv(apdu, &index, INS_STRUCTURE_CHECKSUM, CHECKSUM_SIZE, wallet);
fill_tlv(apdu, &index, INS_MIN_NO_OF_SHARES, 1, wallet);
Expand Down
111 changes: 86 additions & 25 deletions common/interfaces/flash_interface/flash_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,29 @@ bool wallet_is_filled(uint8_t index, wallet_state *state_output) {
return false;
}

bool wallet_is_filled_with_share(uint8_t index) {
if (MAX_WALLETS_ALLOWED <= index) {
return false;
}

/* Make sure that we always work on the latest RAM instance */
get_flash_ram_instance();

wallet_state state = flash_ram_instance.wallets[index].state;
// Read card states without write attempt state
uint8_t cards_states = flash_ram_instance.wallets[index].cards_states & 0x0F;

// If wallet state state is where share is present on device and card state is
// not zero, then wallet is filled
if (((UNVERIFIED_VALID_WALLET == state) || (VALID_WALLET == state) ||
(INVALID_WALLET == state)) &&
(0x00 != cards_states)) {
return true;
}

return false;
}

/**
* @brief Save a new wallet on the flash
*
Expand Down Expand Up @@ -160,7 +183,8 @@ int add_wallet_to_flash(const Flash_Wallet *fwallet, uint32_t *index_OUT) {

int add_wallet_share_to_sec_flash(const Flash_Wallet *fwallet,
uint32_t *index_OUT,
const uint8_t *wallet_share) {
const uint8_t *wallet_share,
const uint8_t *wallet_nonce) {
get_flash_ram_instance(); // to load
get_sec_flash_ram_instance();
if (flash_ram_instance.wallet_count == MAX_WALLETS_ALLOWED)
Expand Down Expand Up @@ -190,6 +214,9 @@ int add_wallet_share_to_sec_flash(const Flash_Wallet *fwallet,
memcpy(sec_flash_instance.wallet_share_data[*index_OUT].wallet_share,
wallet_share,
BLOCK_SIZE);
memcpy(sec_flash_instance.wallet_share_data[*index_OUT].wallet_nonce,
wallet_nonce,
PADDED_NONCE_SIZE);
sec_flash_struct_save();
return SUCCESS_;
}
Expand Down Expand Up @@ -230,7 +257,8 @@ int put_wallet_flash(const uint8_t index, const Flash_Wallet *wallet) {
}

int put_wallet_share_sec_flash(const uint8_t index,
const uint8_t *wallet_share) {
const uint8_t *wallet_share,
const uint8_t *wallet_nonce) {
get_flash_ram_instance(); // to load
get_sec_flash_ram_instance();
if (index >= MAX_WALLETS_ALLOWED)
Expand All @@ -246,6 +274,9 @@ int put_wallet_share_sec_flash(const uint8_t index,
memcpy(sec_flash_instance.wallet_share_data[index].wallet_share,
wallet_share,
BLOCK_SIZE);
memcpy(sec_flash_instance.wallet_share_data[index].wallet_nonce,
wallet_nonce,
PADDED_NONCE_SIZE);
sec_flash_struct_save();
flash_ram_instance.wallets[index].state = VALID_WALLET;
flash_struct_save();
Expand Down Expand Up @@ -531,6 +562,42 @@ int get_flash_wallet_share_by_name(const char *name, uint8_t *wallet_share) {
return DOESNT_EXIST;
}

int get_flash_wallet_nonce_by_name(const char *name, uint8_t *wallet_nonce) {
ASSERT(name != NULL);
ASSERT(wallet_nonce != NULL);

get_flash_ram_instance(); // to load
get_sec_flash_ram_instance();
size_t name_len = strnlen(name, NAME_SIZE);
if (name_len == 0 || name_len >= NAME_SIZE)
return INVALID_ARGUMENT;
uint8_t walletIndex = 0;
for (; walletIndex < MAX_WALLETS_ALLOWED; walletIndex++) {
if (!_wallet_is_filled(walletIndex))
continue;
if (!strcmp(
(const char *)flash_ram_instance.wallets[walletIndex].wallet_name,
name)) {
if (is_wallet_share_not_present(walletIndex))
return DOESNT_EXIST;
for (int i = 0; i < WALLET_ID_SIZE; i++) {
if (flash_ram_instance.wallets[walletIndex].wallet_id[i] !=
sec_flash_instance.wallet_share_data[walletIndex].wallet_id[i]) {
flash_ram_instance.wallets[walletIndex].state =
VALID_WALLET_WITHOUT_DEVICE_SHARE;
flash_struct_save();
return DOESNT_EXIST;
}
}
memcpy(wallet_nonce,
sec_flash_instance.wallet_share_data[walletIndex].wallet_nonce,
BLOCK_SIZE);
return SUCCESS_;
}
}
return DOESNT_EXIST;
}

/**
* @brief Tells if wallet is in partial state
*
Expand Down Expand Up @@ -575,41 +642,35 @@ bool is_wallet_locked(const uint8_t wallet_index) {
}

// TODO: return codes for illegal and all
/**
* @brief Update the card states for the wallet at specified index (on deletion
* of the wallet from the given card number)
*
* @param index
* @param card_number
* @return int
*/
int delete_from_kth_card_flash(const uint8_t index, const uint8_t card_number) {
ASSERT(index < MAX_WALLETS_ALLOWED);

get_flash_ram_instance(); // to load
flash_ram_instance.wallets[index].cards_states &= ~(1 << (card_number - 1));

// Reset card write state
RESET_Ith_BIT(flash_ram_instance.wallets[index].cards_states,
card_number - 1);
// Reset card write attempt state
RESET_Ith_BIT(flash_ram_instance.wallets[index].cards_states,
card_number - 1 + 4);

flash_struct_save();
return SUCCESS_;
}

// TODO: check for illegal arguments and all
/**
* @brief Tells if the wallet at specified index is already deleted from the
* given card number
*
* @param index
* @param card_number
* @return true
* @return false
*/
bool card_already_deleted_flash(const uint8_t index,
const uint8_t card_number) {
ASSERT(index < MAX_WALLETS_ALLOWED);

get_flash_ram_instance(); // to load
return !(
((flash_ram_instance.wallets[index].cards_states) >> (card_number - 1)) &
1);

bool wallet_found_on_card = IS_Ith_BIT_SET(
flash_ram_instance.wallets[index].cards_states, card_number - 1);
bool write_attempted_on_card = IS_Ith_BIT_SET(
flash_ram_instance.wallets[index].cards_states, card_number - 1 + 4);

return !(wallet_found_on_card | write_attempted_on_card);
}

/**
Expand Down Expand Up @@ -663,7 +724,7 @@ int set_wallet_locked(const char *wallet_name, uint8_t encoded_card_number) {
flash_wallet->is_wallet_locked = true;
memzero(&(flash_wallet->challenge), sizeof(flash_wallet->challenge));
flash_wallet->challenge.card_locked = encoded_card_number;
memset(flash_wallet->challenge.nonce, 0xFF, NONCE_SIZE);
memset(flash_wallet->challenge.nonce, 0xFF, PADDED_NONCE_SIZE);
flash_struct_save();
return SUCCESS;
}
Expand Down Expand Up @@ -743,7 +804,7 @@ int update_wallet_locked_flash(const char *name, const bool is_wallet_locked) {
flash_wallet->challenge.time_to_unlock_in_secs = 0;

// Reset nonce to 0xFF as challenge is not fetched
memset(flash_wallet->challenge.nonce, 0xFF, NONCE_SIZE);
memset(flash_wallet->challenge.nonce, 0xFF, PADDED_NONCE_SIZE);
} else {
// Wallet unlocked, reset challenge
memzero(&(flash_wallet->challenge), sizeof(flash_wallet->challenge));
Expand Down
43 changes: 38 additions & 5 deletions common/interfaces/flash_interface/flash_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@
*/
bool wallet_is_filled(uint8_t index, wallet_state *state_output);

/**
* @brief The function checks if a wallet is filled with a share based on its
* index.
*
* @param index The index required to be checked for wallet existance
*
* @return a boolean value. It returns true if the wallet at the given index is
* filled with a share, and false otherwise.
*/
bool wallet_is_filled_with_share(uint8_t index);

/**
* Update auth state and first_boot_on_update variables in firewall
*/
Expand Down Expand Up @@ -64,6 +75,8 @@ int add_wallet_to_flash(const Flash_Wallet *wallet, uint32_t *index_OUT);
*
* @param[in] fwallet a constant reference to an object of type Flash_Wallet
* @param[out] index_OUT index at which share entry is made
* @param[in] wallet_share The 5th share of wallet to be written on device
* @param[in] wallet_nonce Wallet nonce common for all shares
* @return SUCCESS, MEMORY_OVERFLOW, INVALID_ARGUMENT, ALREADY_EXISTS
* @retval SUCCESS Wallet share written to firewall region
* @retval MEMORY_OVERFLOW in case of no empty slots
Expand All @@ -72,8 +85,8 @@ int add_wallet_to_flash(const Flash_Wallet *wallet, uint32_t *index_OUT);
*/
int add_wallet_share_to_sec_flash(const Flash_Wallet *fwallet,
uint32_t *index_OUT,
const uint8_t *wallet_share);

const uint8_t *wallet_share,
const uint8_t *wallet_nonce);
/**
* @brief Deletes a wallet from flash
*
Expand Down Expand Up @@ -172,7 +185,9 @@ int put_wallet_flash(uint8_t index, const Flash_Wallet *wallet);
* @retval INVALID_ARGUMENT non-existent wallet reference or wallet_index >=
* MAX_WALLETS_ALLOWED
*/
int put_wallet_share_sec_flash(uint8_t index, const uint8_t *wallet_share);
int put_wallet_share_sec_flash(uint8_t index,
const uint8_t *wallet_share,
const uint8_t *wallet_nonce);

/**
* @brief Outputs the index of the wallet with given name
Expand Down Expand Up @@ -262,8 +277,23 @@ int get_flash_wallet_by_name(const char *name, Flash_Wallet **flash_wallet_OUT);
int get_flash_wallet_share_by_name(const char *name, uint8_t *wallet_share);

/**
* @brief Update the card states for the wallet at specified index (on deletion
* of the wallet from the given card number)
* Retrieves the wallet nonce associated with a given name from flash memory.
*
* @param name A pointer to a character array representing the name of the
* wallet.
* @param wallet_nonce A pointer to a uint8_t array where the wallet nonce will
* be stored.
*
* @return SUCCESS, INVALID_ARGUMENT, DOESNT_EXIST
* @retval SUCCESS Wallet found & wallet share returned
* @retval INVALID_ARGUMENT Passed name is invalid
* @retval DOESNT_EXIST Wallet does not exist with given name
*/
int get_flash_wallet_nonce_by_name(const char *name, uint8_t *wallet_nonce);

/**
* @brief Update the card states(write and attempt states) for the wallet at
* specified index (on deletion of the wallet from the given card number)
*
* @param index Wallet index in flash
* @param card_number Card number to delete
Expand All @@ -275,6 +305,9 @@ int delete_from_kth_card_flash(uint8_t index, uint8_t card_number);
* @brief Tells if the wallet at specified index is already deleted from the
* given card number
*
* @details This function checks the write state and attempt state of the wallet
* to be deleted.
*
* @param index Wallet index in flash
* @param card_number Card number to check
* @return true, false
Expand Down
Loading

0 comments on commit 1eb7daf

Please sign in to comment.