1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 15:38:11 +00:00

core/sd-protect: Add SD_CARD_HOT_SWAPPABLE option and improve error handling.

This commit is contained in:
Andrew Kozlik 2019-09-24 15:32:39 +02:00
parent 710866074b
commit 795fa07822
2 changed files with 103 additions and 75 deletions

View File

@ -3,12 +3,12 @@ from micropython import const
from trezor import io, ui, wire
from trezor.crypto import hmac
from trezor.crypto.hashlib import sha256
from trezor.ui.confirm import Confirm
from trezor.ui.confirm import CONFIRMED, Confirm
from trezor.ui.text import Text
from trezor.utils import consteq
from apps.common import storage
from apps.common.confirm import require_confirm
from apps.common.confirm import confirm
if False:
from typing import Optional
@ -18,6 +18,7 @@ class SdProtectCancelled(Exception):
pass
SD_CARD_HOT_SWAPPABLE = False
SD_SALT_LEN_BYTES = const(32)
SD_SALT_AUTH_TAG_LEN_BYTES = const(16)
SD_SALT_AUTH_KEY_LEN_BYTES = const(16)
@ -27,22 +28,53 @@ async def _wrong_card_dialog(ctx: Optional[wire.Context]) -> None:
text = Text("SD card protection", ui.ICON_WRONG)
text.bold("Wrong SD card.")
text.br_half()
text.normal("Please unplug the", "device and insert a", "different card.")
if ctx is None:
await Confirm(text, confirm=None, cancel="Close")
if SD_CARD_HOT_SWAPPABLE:
text.normal("Please insert the", "correct SD card for", "this device.")
btn_confirm = "Retry"
btn_cancel = "Abort"
else:
await require_confirm(ctx, text, confirm=None, cancel="Close")
text.normal("Please unplug the", "device and insert the", "correct SD card.")
btn_confirm = None
btn_cancel = "Close"
if ctx is None:
if await Confirm(text, confirm=btn_confirm, cancel=btn_cancel) is not CONFIRMED:
raise SdProtectCancelled
else:
if not await confirm(ctx, text, confirm=btn_confirm, cancel=btn_cancel):
raise wire.ProcessError("Wrong SD card.")
async def _insert_card_dialog(ctx: Optional[wire.Context]) -> None:
text = Text("SD card protection")
text = Text("SD card protection", ui.ICON_WRONG)
text.bold("SD card required.")
text.br_half()
if SD_CARD_HOT_SWAPPABLE:
text.normal("Please insert your", "SD card.")
btn_confirm = "Retry"
btn_cancel = "Abort"
else:
text.normal("Please unplug the", "device and insert your", "SD card.")
btn_confirm = None
btn_cancel = "Close"
if ctx is None:
if await Confirm(text, confirm=btn_confirm, cancel=btn_cancel) is not CONFIRMED:
raise SdProtectCancelled
else:
if not await confirm(ctx, text, confirm=btn_confirm, cancel=btn_cancel):
raise wire.ProcessError("SD card required.")
async def _write_failed_dialog(ctx: Optional[wire.Context]) -> None:
text = Text("SD card protection", ui.ICON_WRONG, ui.RED)
text.normal("Failed to write data to", "the SD card.")
if ctx is None:
await Confirm(text, confirm=None, cancel="Close")
raise OSError
else:
await require_confirm(ctx, text, confirm=None, cancel="Close")
await confirm(ctx, text, confirm=None, cancel="Close")
raise wire.ProcessError("Failed to write to SD card.")
def _get_device_dir() -> str:
@ -62,11 +94,11 @@ async def request_sd_salt(
salt_path = _get_salt_path()
new_salt_path = _get_salt_path(True)
while True:
sd = io.SDCard()
fs = io.FatFS()
if not sd.power(True):
while not sd.power(True):
await _insert_card_dialog(ctx)
raise SdProtectCancelled
try:
fs.mount()
@ -83,7 +115,9 @@ async def request_sd_salt(
salt = None
if salt is not None and consteq(
hmac.new(salt_auth_key, salt, sha256).digest()[:SD_SALT_AUTH_TAG_LEN_BYTES],
hmac.new(salt_auth_key, salt, sha256).digest()[
:SD_SALT_AUTH_TAG_LEN_BYTES
],
salt_tag,
):
return salt
@ -118,7 +152,6 @@ async def request_sd_salt(
sd.power(False)
await _wrong_card_dialog(ctx)
raise SdProtectCancelled
async def set_sd_salt(
@ -127,9 +160,8 @@ async def set_sd_salt(
salt_path = _get_salt_path(new)
sd = io.SDCard()
if not sd.power(True):
while not sd.power(True):
await _insert_card_dialog(ctx)
raise SdProtectCancelled
fs = io.FatFS()
@ -140,7 +172,11 @@ async def set_sd_salt(
with fs.open(salt_path, "w") as f:
f.write(salt)
f.write(salt_tag)
finally:
except Exception:
fs.unmount()
sd.power(False)
await _write_failed_dialog(ctx)
fs.unmount()
sd.power(False)
@ -158,8 +194,7 @@ async def commit_sd_salt(ctx: Optional[wire.Context]) -> None:
sd = io.SDCard()
fs = io.FatFS()
if not sd.power(True):
await _insert_card_dialog(ctx)
raise SdProtectCancelled
raise IOError
try:
fs.mount()
@ -180,8 +215,7 @@ async def remove_sd_salt(ctx: Optional[wire.Context]) -> None:
sd = io.SDCard()
fs = io.FatFS()
if not sd.power(True):
await _insert_card_dialog(ctx)
raise SdProtectCancelled
raise IOError
try:
fs.mount()

View File

@ -62,10 +62,7 @@ async def sd_protect_enable(ctx: wire.Context, msg: SdProtect) -> Success:
salt_tag = hmac.new(salt_auth_key, salt, sha256).digest()[
:SD_SALT_AUTH_TAG_LEN_BYTES
]
try:
await set_sd_salt(ctx, salt, salt_tag)
except Exception:
raise wire.ProcessError("Failed to write to SD card")
if not config.change_pin(pin, pin, None, salt):
# Wrong PIN. Clean up the prepared salt file.
@ -131,10 +128,7 @@ async def sd_protect_refresh(ctx: wire.Context, msg: SdProtect) -> Success:
new_salt_tag = hmac.new(new_salt_auth_key, new_salt, sha256).digest()[
:SD_SALT_AUTH_TAG_LEN_BYTES
]
try:
await stage_sd_salt(ctx, new_salt, new_salt_tag)
except Exception:
raise wire.ProcessError("Failed to write to SD card")
if not config.change_pin(pin_to_int(pin), pin_to_int(pin), old_salt, new_salt):
await show_pin_invalid(ctx)