block some USB command in hobble mode

This commit is contained in:
Peter D. Gray 2025-09-10 10:45:36 -04:00 committed by doc-hex
parent 4bd8d12d9d
commit 54d58d4b43
3 changed files with 77 additions and 30 deletions

View File

@ -19,10 +19,10 @@ class CCBusyError(RuntimeError):
# HSM is blocking your action
class HSMDenied(RuntimeError):
pass
class HSMCMDDisabled(RuntimeError):
pass
# PSBT / transaction related
class FatalPSBTIssue(RuntimeError):
pass
@ -51,7 +51,7 @@ class QRDecodeExplained(ValueError):
class UnknownAddressExplained(ValueError):
pass
# We're not going to co-sign using CCC feature
# We're not going to co-sign using spending policy features
class SpendPolicyViolation(RuntimeError):
pass

View File

@ -11,7 +11,8 @@ from ustruct import pack, unpack_from
from ckcc import watchpoint, is_simulator
from utils import problem_file_line, call_later_ms
from version import supports_hsm, is_devmode, MAX_TXN_LEN, MAX_UPLOAD_LEN
from exceptions import FramingError, CCBusyError, HSMDenied, HSMCMDDisabled
from exceptions import FramingError, CCBusyError, HSMDenied, HSMCMDDisabled, SpendPolicyViolation
from pincodes import pa
# Unofficial, unpermissioned... numbers
COINKITE_VID = 0xd13e
@ -68,6 +69,21 @@ HSM_DISABLE_CMDS = frozenset({
"hsms",
})
# spending policy active: blacklist some commands
# - 'pass' may be allowed if 'okeys' is enabled
HOBBLED_CMDS = frozenset({
'enrl', # no new multisigs during policy enforcement
'back', # no backups
'bagi', 'dfu_', # just in case
"user", # same as HSM_DISABLE_CMDS
"rmur",
"nwur",
"gslr",
"hsts",
"hsms",
})
# singleton instance of USBHandler()
handler = None
@ -217,6 +233,8 @@ class USBHandler:
except CCBusyError:
# auth UX is doing something else
resp = b'busy'
except SpendPolicyViolation:
resp = b'err_Spending policy in effect'
except HSMDenied:
resp = b'err_Not allowed in HSM mode'
except HSMCMDDisabled:
@ -345,7 +363,7 @@ class USBHandler:
except:
raise FramingError('decode')
if cmd[0].isupper() and is_devmode:
if is_devmode and cmd[0].isupper():
# special hacky commands to support testing w/ the simulator
try:
from usb_test_commands import do_usb_command
@ -358,7 +376,18 @@ class USBHandler:
if cmd not in HSM_WHITELIST:
raise HSMDenied
if not settings.get('hsmcmd', False):
if pa.hobbled_mode:
# block some commands when we are hobbled.
if cmd in HOBBLED_CMDS:
raise SpendPolicyViolation
if cmd in {'pwok', 'pass'}:
from ccc import sssp_spending_policy
if not sssp_spending_policy('okeys'):
raise SpendPolicyViolation
elif not settings.get('hsmcmd', False):
# block these HSM-related command if not using feature
if cmd in HSM_DISABLE_CMDS:
raise HSMCMDDisabled
@ -741,7 +770,6 @@ class USBHandler:
from glob import dis, hsm_active
from utils import check_firmware_hdr
from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE, FW_HEADER_MAGIC
from pincodes import pa
# maintain a running SHA256 over what's received
if offset == 0:
@ -754,8 +782,8 @@ class USBHandler:
assert offset % 256 == 0, 'alignment'
assert offset+len(data) <= total_size <= MAX_UPLOAD_LEN, 'long'
if hsm_active:
# additional restrictions in HSM mode
if hsm_active or pa.hobbled_mode:
# additional restriction in HSM mode or hobbled: must be PSBT
assert offset+len(data) <= total_size <= MAX_TXN_LEN, 'psbt'
if offset == 0:
assert data[0:5] == b'psbt\xff', 'psbt'
@ -834,7 +862,6 @@ class USBHandler:
def handle_bag_number(self, bag_num):
import version, callgate
from glob import dis, settings
from pincodes import pa
if bag_num and version.is_factory_mode and not version.has_qr:
# check state first

View File

@ -12,26 +12,6 @@ from test_ephemeral import SEEDVAULT_TEST_DATA, WORDLISTS
from test_ephemeral import confirm_tmp_seed, verify_ephemeral_secret_ui
from test_ux import word_menu_entry
'''
TODO -- When hobbled...
- login sequence
1) system has lgto value: should get bypass pin, main pin, delay, then main pin again
2) using a trick PIN with delay, after bypass pin should delay
3) bypass pin + duress wallet PIN => should work => but not a useful trick combo
- word entry during login
- q1 vs mk4 style
- wrong values given, etc
- verify whitelist of QR types is correct when in hobbled mode
- no private key material, no teleport starting, unless "okeys" is set
- TODO: update menu tree w/ hobble mode view
- verify that PSBT can be "signed" when SP enabled and delta-mode pin is active. seed not wiped.
'''
# NOTE: these are unit tests of the effects of hobble mode, not how it is enabled/disabled:
#
@ -386,6 +366,46 @@ def test_h_tempseeds(mode, set_hobble, pick_menu_item, cap_menu, settings_set, i
pick_menu_item("Restore Master")
press_select()
# TODO: test usb commands are blocked
@pytest.mark.parametrize('en_okeys', [ True, False])
def test_h_usbcmds(en_okeys, set_hobble, dev):
# test various usb commands are blocked during hobble
from ckcc_protocol.protocol import CCProtoError
set_hobble(True, {'okeys'} if en_okeys else {})
block_list = [
'back', 'enrl', 'bagi', 'hsms', 'user', 'nwur', 'rmur',
]
if not en_okeys:
block_list.insert(0, 'pass')
for cmd in block_list:
with pytest.raises(CCProtoError) as ee:
got = dev.send_recv(cmd)
assert 'Spending policy in effect' in str(ee)
# TODO: verify that PSBT can be "signed" when SP enabled and delta-mode pin is active. seed not wiped.
# TODO verify whitelist of QR types is correct when in hobbled mode
# - no private key material, no teleport starting, unless "okeys" is set
# TODO Special Login Sequence
'''
- login sequence
1) system has lgto value: should get bypass pin, main pin, delay, then main pin again
2) using a trick PIN with delay, after bypass pin should delay
3) bypass pin + duress wallet PIN => should work => but not a useful trick combo
- word entry during login
- q1 vs mk4 style
- wrong values given, etc
'''
# EOF