Skip to content

Commit ee9369f

Browse files
committed
test(reset): assert an aborted reset disarms EntropyAck
Regression cover for a host-controllable seed: reset_init aborts left awaiting_entropy armed from an earlier ResetDevice while zeroing int_entropy, so a following EntropyAck derived the seed from sha256(0*32 || host_bytes). The test arms a reset, re-enters with dice_entropy, cancels, and requires the EntropyAck to fail with 'Not in Reset mode' with the device still uninitialized.
1 parent 58d4e02 commit ee9369f

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

‎tests/test_msg_resetdevice.py‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,48 @@ def test_reset_device_dice(self):
192192
self.assertIsInstance(resp, proto.Success)
193193
self.assertEqual(' '.join(mnemonic), expected_mnemonic)
194194

195+
def test_reset_reentry_disarms_entropy_ack(self):
196+
"""An aborted reset must not leave EntropyAck armed.
197+
198+
Regression: reset_init aborts (dice cancel, PIN mismatch, ...) left
199+
awaiting_entropy set from an earlier run while zeroing int_entropy,
200+
so a following EntropyAck derived the seed from
201+
sha256(0*32 || host_bytes) -- entirely host-chosen.
202+
"""
203+
self.requires_firmware("7.15.0")
204+
self.client.wipe_device()
205+
206+
# Arm a reset and walk away without acking the entropy request.
207+
ret = self.client.call_raw(proto.ResetDevice(display_random=False,
208+
strength=256,
209+
passphrase_protection=False,
210+
pin_protection=False,
211+
language='english',
212+
label='first'))
213+
self.assertIsInstance(ret, proto.EntropyRequest)
214+
215+
# Re-enter with dice, then abort from the host.
216+
ret = self.client.call_raw(proto.ResetDevice(display_random=False,
217+
strength=256,
218+
passphrase_protection=False,
219+
pin_protection=False,
220+
language='english',
221+
label='second',
222+
dice_entropy=True))
223+
self.assertIsInstance(ret, proto.ButtonRequest)
224+
self.assertEqual(ret.code, proto_types.ButtonRequest_DiceRoll)
225+
ret = self.client.call_raw(proto.Cancel())
226+
self.assertIsInstance(ret, proto.Failure)
227+
228+
# The abandoned reset must be disarmed, so this cannot generate a seed.
229+
ret = self.client.call_raw(proto.EntropyAck(entropy=b'H' * 32))
230+
self.assertIsInstance(ret, proto.Failure)
231+
self.assertIn('Not in Reset mode', ret.message)
232+
233+
# And the device must still be uninitialized.
234+
ret = self.client.call_raw(proto.Initialize())
235+
self.assertFalse(ret.initialized)
236+
195237
def test_reset_device_pin(self):
196238
external_entropy = b'zlutoucky kun upel divoke ody' * 2
197239
strength = 128

0 commit comments

Comments
 (0)