diff --git a/ports/stm32/boards/Passport/modfoundation.c b/ports/stm32/boards/Passport/modfoundation.c index 98defb5..7fab79d 100644 --- a/ports/stm32/boards/Passport/modfoundation.c +++ b/ports/stm32/boards/Passport/modfoundation.c @@ -1388,6 +1388,18 @@ System_get_user_firmware_pubkey(mp_obj_t self, mp_obj_t pubkey) return mp_const_false; } +/// def is_user_firmware_installed(self) -> None +/// ''' +/// Check if user firmware is installed or not +/// ''' +STATIC mp_obj_t +System_is_user_firmware_installed(mp_obj_t self) +{ + passport_firmware_header_t* fwhdr = (passport_firmware_header_t*)FW_HDR; + + return (fwhdr->signature.pubkey1 == FW_USER_KEY && fwhdr->signature.pubkey2 == 0) ? mp_const_true : mp_const_false; +} + /// def System_supply_chain_challenge(self, challenge, response) -> None /// ''' /// Perform the supply chain challenge (HMAC) @@ -1572,6 +1584,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_sha256_obj, System_sha256); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_validate_firmware_header_obj, System_validate_firmware_header); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_set_user_firmware_pubkey_obj, System_set_user_firmware_pubkey); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_get_user_firmware_pubkey_obj, System_get_user_firmware_pubkey); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_is_user_firmware_installed_obj, System_is_user_firmware_installed); STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_supply_chain_challenge_obj, System_supply_chain_challenge); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(System_hmac_sha256_obj, 4, 4, System_hmac_sha256); STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_verify_supply_chain_server_signature_obj, System_verify_supply_chain_server_signature); @@ -1603,6 +1616,7 @@ STATIC const mp_rom_map_elem_t System_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_validate_firmware_header), MP_ROM_PTR(&System_validate_firmware_header_obj) }, { MP_ROM_QSTR(MP_QSTR_set_user_firmware_pubkey), MP_ROM_PTR(&System_set_user_firmware_pubkey_obj) }, { MP_ROM_QSTR(MP_QSTR_get_user_firmware_pubkey), MP_ROM_PTR(&System_get_user_firmware_pubkey_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_user_firmware_installed), MP_ROM_PTR(&System_is_user_firmware_installed_obj) }, { MP_ROM_QSTR(MP_QSTR_supply_chain_challenge), MP_ROM_PTR(&System_supply_chain_challenge_obj) }, { MP_ROM_QSTR(MP_QSTR_verify_supply_chain_server_signature), MP_ROM_PTR(&System_verify_supply_chain_server_signature_obj) }, { MP_ROM_QSTR(MP_QSTR_hmac_sha256), MP_ROM_PTR(&System_hmac_sha256_obj) }, diff --git a/ports/stm32/boards/Passport/modules/actions.py b/ports/stm32/boards/Passport/modules/actions.py index 7ce0e51..b296526 100644 --- a/ports/stm32/boards/Passport/modules/actions.py +++ b/ports/stm32/boards/Passport/modules/actions.py @@ -22,7 +22,8 @@ import common from common import settings, system, noise, dis from utils import (UXStateMachine, imported, pretty_short_delay, xfp2str, to_str, truncate_string_to_width, set_next_addr, scan_for_address, get_accounts, run_chooser, - make_account_name_num, is_valid_address, save_next_addr, needs_microsd, format_btc_address) + make_account_name_num, is_valid_address, save_next_addr, needs_microsd, format_btc_address, + is_all_zero, bytes_to_hex_str, split_to_lines) from wallets.utils import get_export_mode, get_addr_type_from_address, get_deriv_path_from_addr_type_and_acct from ux import (the_ux, ux_confirm, ux_enter_pin, ux_enter_text, ux_scan_qr_code, ux_shutdown, @@ -1396,53 +1397,14 @@ async def handle_psbt_data_format(data): return False -async def import_user_firmware_pubkey(*a): - from common import system, dis - from ubinascii import hexlify - - result = await ux_show_story('''Passport allows you to compile your own firmware version and sign it \ -with your private key. - -To enable this, you must first import your corresponding public key. - -On the next screen, you can select your public key and import it into Passport.''', title='Import PubKey') - if result == 'x': - return - - fn = await file_picker('Select public key file (*-pub.bin)', suffix='-pub.bin') - if fn == None: - return - - system.turbo(True) - with CardSlot() as card: - with open(fn, 'rb') as fd: - fd.seek(24) # Skip the header - pubkey = fd.read(64) # Read the pubkey - - # print('pubkey = {}'.format(hexlify(pubkey))) - - result = system.set_user_firmware_pubkey(pubkey) - if result: - dis.fullscreen('Successfully Imported!') - else: - dis.fullscreen('Unable to Import') - await sleep_ms(1000) - # print('system.set_user_firmware_pubkey() = {}'.format(result)) - system.turbo(False) - - -async def read_user_firmware_pubkey(*a): - from common import system - from ubinascii import hexlify - +def read_user_firmware_pubkey(): pubkey = bytearray(64) system.turbo(True) result = system.get_user_firmware_pubkey(pubkey) - # print('system.get_user_firmware_pubkey() = {}'.format(result)) - # print(' len={} pubkey = {}'.format(len(pubkey), hexlify(pubkey))) system.turbo(False) + return result, pubkey async def enter_passphrase(menu, label, item): import sys @@ -1458,7 +1420,6 @@ async def enter_passphrase(menu, label, item): return # Applying the passphrase takes a bit of time so show message - from common import dis dis.fullscreen("Applying Passphrase...") system.show_busy_bar() @@ -2040,3 +2001,85 @@ async def set_last_verified_addr(*a): from public_constants import AF_P2WPKH save_next_addr(0, AF_P2WPKH, 76, False) + +def clear_cached_pubkey(): + common.cached_pubkey = None + +async def install_user_firmware_pubkey(*a): + from ubinascii import hexlify + + result = await ux_show_story('''Passport allows you to compile your own firmware version and sign it \ +with your private key. + +To enable this, you must first import your corresponding public key. + +On the next screen, you can select your public key and import it into Passport.''', title='Import PubKey') + if result == 'x': + return + + fn = await file_picker('Select public key file (*-pub.bin)', suffix='-pub.bin') + if fn == None: + return + + system.turbo(True) + with CardSlot() as card: + with open(fn, 'rb') as fd: + fd.seek(24) # Skip the header + pubkey = fd.read(64) # Read the pubkey + + # print('pubkey = {}'.format(hexlify(pubkey))) + + result = system.set_user_firmware_pubkey(pubkey) + if result: + await ux_show_story('Successfully Installed!', + title='Install', + center=True, + center_vertically=True) + else: + await ux_show_story('Unable to Install.', + title='Install', + center=True, + center_vertically=True) + clear_cached_pubkey() + + # print('system.set_user_firmware_pubkey() = {}'.format(result)) + system.turbo(False) + +async def view_user_firmware_pubkey(*a): + pubkey_result, pubkey = read_user_firmware_pubkey() + if pubkey_result: + pubkey = bytes_to_hex_str(pubkey) + pubkey = split_to_lines(pubkey, 16) + else: + pubkey = 'Unable to read Developer PubKey' + + result = await ux_show_story(pubkey, + title='View PubKey', + center=True, + center_vertically=True) + if result == 'x': + return + +async def remove_user_firmware_pubkey(*a): + if system.is_user_firmware_installed(): + await ux_show_story('You must install official Foundation firmware before you can remove the Developer PubKey.', + title='Remove', + center=True, + center_vertically=True) + return + + pubkey = bytearray(64) + # Confirm the user knows the potential consequences + if await ux_confirm('Are you sure you want to remove the Developer PubKey?', title='Remove'): + result = system.set_user_firmware_pubkey(pubkey) + if result: + await ux_show_story('Successfully Removed PubKey!', + title='Remove', + center=True, + center_vertically=True) + else: + await ux_show_story('Unable to Remove PubKey', + title='Remove', + center=True, + center_vertically=True) + clear_cached_pubkey() \ No newline at end of file diff --git a/ports/stm32/boards/Passport/modules/common.py b/ports/stm32/boards/Passport/modules/common.py index a879548..5897611 100644 --- a/ports/stm32/boards/Passport/modules/common.py +++ b/ports/stm32/boards/Passport/modules/common.py @@ -67,3 +67,6 @@ is_new_wallet_a_duplicate = False # The QRTYpe of the last QR code that was scanned last_scanned_qr_type = None last_scanned_ur_prefix = None + +# Cached Developer PubKey +cached_pubkey = None \ No newline at end of file diff --git a/ports/stm32/boards/Passport/modules/flow.py b/ports/stm32/boards/Passport/modules/flow.py index d4b3081..74e4b3a 100644 --- a/ports/stm32/boards/Passport/modules/flow.py +++ b/ports/stm32/boards/Passport/modules/flow.py @@ -45,13 +45,26 @@ def has_secrets(): from common import pa return not pa.is_secret_blank() +def has_pubkey(): + if common.cached_pubkey == None: + result, common.cached_pubkey = read_user_firmware_pubkey() + if not result: + return False + return not is_all_zero(common.cached_pubkey) + +DeveloperPubkeyMenu = [ + MenuItem('Install PubKey', predicate=lambda: not has_pubkey(), f=install_user_firmware_pubkey), + MenuItem('View PubKey', predicate=has_pubkey, f=view_user_firmware_pubkey), + MenuItem('Remove PubKey', predicate=has_pubkey, f=remove_user_firmware_pubkey) +] + AdvancedMenu = [ MenuItem('Change PIN', f=change_pin), MenuItem('Passphrase', menu_title='Passphrase', chooser=enable_passphrase_chooser), MenuItem('Sign Text File', predicate=has_secrets, f=sign_message_on_sd), MenuItem('MicroSD Settings', menu=SDCardMenu), MenuItem('View Seed Words', f=view_seed_words, predicate=lambda: settings.get('words', True)), - MenuItem('Developer PubKey', f=import_user_firmware_pubkey), + MenuItem('Developer PubKey', menu=DeveloperPubkeyMenu, menu_title='Developer'), MenuItem('Erase Passport', f=erase_wallet, arg=True) ] diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 0915888..43c88be 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -821,9 +821,18 @@ def format_btc_address(address, addr_type): else: width = 16 - return '\n'.join([address[i:i+width] for i in range(0, len(address), width)]) + return split_to_lines(address, width) def get_backups_folder_path(card): return '{}/backups'.format(card.get_sd_root()) +def is_all_zero(buf): + for b in buf: + if b != 0: + return False + return True + +def split_to_lines(s, width): + return '\n'.join([s[i:i+width] for i in range(0, len(s), width)]) + # EOF