1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-16 11:28:14 +00:00

core: Move some PIN-related functions to apps.common.request_pin and implement verify_user_pin().

This commit is contained in:
Andrew Kozlik 2019-09-16 23:08:42 +02:00
parent 3c20b1b1cd
commit f5ea81f905
7 changed files with 100 additions and 70 deletions

View File

@ -1,5 +1,17 @@
from trezor import loop from trezor import config, loop, ui, wire
from trezor.messages import ButtonRequestType
from trezor.messages.ButtonAck import ButtonAck
from trezor.messages.ButtonRequest import ButtonRequest
from trezor.pin import pin_to_int
from trezor.ui.pin import CANCELLED, PinDialog from trezor.ui.pin import CANCELLED, PinDialog
from trezor.ui.popup import Popup
from trezor.ui.text import Text
from apps.common.sd_salt import request_sd_salt
from apps.common.storage import device
if False:
from typing import Any, Optional, Tuple
if __debug__: if __debug__:
from apps.debug import input_signal from apps.debug import input_signal
@ -9,6 +21,10 @@ class PinCancelled(Exception):
pass pass
class PinInvalid(Exception):
pass
async def request_pin( async def request_pin(
prompt: str = "Enter your PIN", prompt: str = "Enter your PIN",
attempts_remaining: int = None, attempts_remaining: int = None,
@ -31,3 +47,68 @@ async def request_pin(
if result is CANCELLED: if result is CANCELLED:
raise PinCancelled raise PinCancelled
return result return result
async def request_pin_ack(ctx: wire.Context, *args: Any, **kwargs: Any) -> str:
try:
await ctx.call(ButtonRequest(code=ButtonRequestType.Other), ButtonAck)
return await ctx.wait(request_pin(*args, **kwargs))
except PinCancelled:
raise wire.ActionCancelled("Cancelled")
async def request_pin_confirm(ctx: wire.Context, *args: Any, **kwargs: Any) -> str:
while True:
pin1 = await request_pin_ack(ctx, "Enter new PIN", *args, **kwargs)
pin2 = await request_pin_ack(ctx, "Re-enter new PIN", *args, **kwargs)
if pin1 == pin2:
return pin1
await pin_mismatch()
async def pin_mismatch() -> None:
text = Text("PIN mismatch", ui.ICON_WRONG, ui.RED)
text.normal("The PINs you entered", "do not match.")
text.normal("")
text.normal("Please try again.")
popup = Popup(text, 3000) # show for 3 seconds
await popup
async def request_pin_and_sd_salt(
ctx: wire.Context, prompt: str = "Enter your PIN", allow_cancel: bool = True
) -> Tuple[str, Optional[bytearray]]:
salt_auth_key = device.get_sd_salt_auth_key()
if salt_auth_key is not None:
salt = await request_sd_salt(ctx, salt_auth_key) # type: Optional[bytearray]
else:
salt = None
if config.has_pin():
pin = await request_pin_ack(ctx, prompt, config.get_pin_rem(), allow_cancel)
else:
pin = ""
return pin, salt
async def verify_user_pin(
prompt: str = "Enter your PIN", allow_cancel: bool = True, retry: bool = True
) -> None:
salt_auth_key = device.get_sd_salt_auth_key()
if salt_auth_key is not None:
salt = await request_sd_salt(None, salt_auth_key) # type: Optional[bytearray]
else:
salt = None
if not config.has_pin() and not config.check_pin(pin_to_int(""), salt):
raise RuntimeError
while retry:
pin = await request_pin(prompt, config.get_pin_rem(), allow_cancel)
if config.check_pin(pin_to_int(pin), salt):
return
else:
prompt = "Wrong PIN, enter again"
raise PinInvalid

View File

@ -1,19 +1,12 @@
from trezor import config, ui, wire from trezor import config, ui, wire
from trezor.messages import ButtonRequestType
from trezor.messages.ButtonAck import ButtonAck
from trezor.messages.ButtonRequest import ButtonRequest
from trezor.messages.Success import Success from trezor.messages.Success import Success
from trezor.pin import pin_to_int from trezor.pin import pin_to_int
from trezor.ui.popup import Popup
from trezor.ui.text import Text from trezor.ui.text import Text
from apps.common.confirm import require_confirm from apps.common.confirm import require_confirm
from apps.common.request_pin import PinCancelled, request_pin from apps.common.request_pin import request_pin_and_sd_salt, request_pin_confirm
from apps.common.sd_salt import request_sd_salt
from apps.common.storage import device
if False: if False:
from typing import Any, Optional, Tuple
from trezor.messages.ChangePin import ChangePin from trezor.messages.ChangePin import ChangePin
@ -65,46 +58,3 @@ def require_confirm_change_pin(ctx: wire.Context, msg: ChangePin) -> None:
text.normal("Do you really want to") text.normal("Do you really want to")
text.bold("enable PIN protection?") text.bold("enable PIN protection?")
return require_confirm(ctx, text) return require_confirm(ctx, text)
async def request_pin_confirm(ctx: wire.Context, *args: Any, **kwargs: Any) -> str:
while True:
pin1 = await request_pin_ack(ctx, "Enter new PIN", *args, **kwargs)
pin2 = await request_pin_ack(ctx, "Re-enter new PIN", *args, **kwargs)
if pin1 == pin2:
return pin1
await pin_mismatch()
async def request_pin_and_sd_salt(
ctx: wire.Context, prompt: str = "Enter your PIN", allow_cancel: bool = True
) -> Tuple[str, Optional[bytearray]]:
salt_auth_key = device.get_sd_salt_auth_key()
if salt_auth_key is not None:
salt = await request_sd_salt(ctx, salt_auth_key) # type: Optional[bytearray]
else:
salt = None
if config.has_pin():
pin = await request_pin_ack(ctx, prompt, config.get_pin_rem(), allow_cancel)
else:
pin = ""
return pin, salt
async def request_pin_ack(ctx: wire.Context, *args: Any, **kwargs: Any) -> str:
try:
await ctx.call(ButtonRequest(code=ButtonRequestType.Other), ButtonAck)
return await ctx.wait(request_pin(*args, **kwargs))
except PinCancelled:
raise wire.ActionCancelled("Cancelled")
async def pin_mismatch() -> None:
text = Text("PIN mismatch", ui.ICON_WRONG, ui.RED)
text.normal("The PINs you entered", "do not match.")
text.normal("")
text.normal("Please try again.")
popup = Popup(text, 3000) # show for 3 seconds
await popup

View File

@ -6,7 +6,7 @@ from trezor.ui.text import Text
from apps.common import storage from apps.common import storage
from apps.common.confirm import require_confirm from apps.common.confirm import require_confirm
from apps.management.change_pin import request_pin_and_sd_salt, request_pin_confirm from apps.common.request_pin import request_pin_and_sd_salt, request_pin_confirm
from apps.management.recovery_device.homescreen import recovery_process from apps.management.recovery_device.homescreen import recovery_process
if False: if False:

View File

@ -10,7 +10,7 @@ from trezor.ui.text import Text
from apps.common import mnemonic, storage from apps.common import mnemonic, storage
from apps.common.confirm import require_confirm from apps.common.confirm import require_confirm
from apps.management.change_pin import request_pin_confirm from apps.common.request_pin import request_pin_confirm
from apps.management.common import layout from apps.management.common import layout
if __debug__: if __debug__:

View File

@ -7,6 +7,7 @@ from trezor.pin import pin_to_int
from trezor.ui.text import Text from trezor.ui.text import Text
from apps.common.confirm import require_confirm from apps.common.confirm import require_confirm
from apps.common.request_pin import request_pin_ack, request_pin_and_sd_salt
from apps.common.sd_salt import ( from apps.common.sd_salt import (
SD_SALT_AUTH_KEY_LEN_BYTES, SD_SALT_AUTH_KEY_LEN_BYTES,
SD_SALT_AUTH_TAG_LEN_BYTES, SD_SALT_AUTH_TAG_LEN_BYTES,
@ -17,7 +18,6 @@ from apps.common.sd_salt import (
stage_sd_salt, stage_sd_salt,
) )
from apps.common.storage import device, is_initialized from apps.common.storage import device, is_initialized
from apps.management.change_pin import request_pin_ack, request_pin_and_sd_salt
if False: if False:
from trezor.messages.SdProtect import SdProtect from trezor.messages.SdProtect import SdProtect

View File

@ -512,20 +512,15 @@ class KeepaliveCallback:
send_cmd_sync(cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING), self.iface) send_cmd_sync(cmd_keepalive(self.cid, _KEEPALIVE_STATUS_PROCESSING), self.iface)
async def check_pin(keepalive_callback: KeepaliveCallback) -> bool: async def verify_user(keepalive_callback: KeepaliveCallback) -> bool:
from apps.common.request_pin import PinCancelled, request_pin from apps.common.request_pin import verify_user_pin, PinCancelled, PinInvalid
import trezor.pin import trezor.pin
try: try:
trezor.pin.keepalive_callback = keepalive_callback trezor.pin.keepalive_callback = keepalive_callback
if config.has_pin(): await verify_user_pin()
pin = await request_pin("Enter your PIN", config.get_pin_rem()) ret = True
while config.unlock(trezor.pin.pin_to_int(pin)) is not True: except (PinCancelled, PinInvalid):
pin = await request_pin("Wrong PIN, enter again", config.get_pin_rem())
ret = True
else:
ret = config.unlock(trezor.pin.pin_to_int(""))
except PinCancelled:
ret = False ret = False
finally: finally:
trezor.pin.keepalive_callback = None trezor.pin.keepalive_callback = None
@ -695,7 +690,7 @@ class Fido2ConfirmMakeCredential(Fido2State, ConfirmInfo):
if not await confirm(content): if not await confirm(content):
return False return False
if self._user_verification: if self._user_verification:
return await check_pin(KeepaliveCallback(self.cid, self.iface)) return await verify_user(KeepaliveCallback(self.cid, self.iface))
return True return True
async def on_confirm(self) -> None: async def on_confirm(self) -> None:
@ -764,7 +759,7 @@ class Fido2ConfirmGetAssertion(Fido2State, ConfirmInfo, Pageable):
if await ConfirmPageable(self, content) is not CONFIRMED: if await ConfirmPageable(self, content) is not CONFIRMED:
return False return False
if self._user_verification: if self._user_verification:
return await check_pin(KeepaliveCallback(self.cid, self.iface)) return await verify_user(KeepaliveCallback(self.cid, self.iface))
return True return True
async def on_confirm(self) -> None: async def on_confirm(self) -> None:

View File

@ -12,7 +12,7 @@ from trezor.ui.button import (
) )
if False: if False:
from typing import Iterable from typing import Iterable, Optional
def digit_area(i: int) -> ui.Area: def digit_area(i: int) -> ui.Area:
@ -30,7 +30,7 @@ def generate_digits() -> Iterable[int]:
class PinInput(ui.Component): class PinInput(ui.Component):
def __init__(self, prompt: str, subprompt: str, pin: str) -> None: def __init__(self, prompt: str, subprompt: Optional[str], pin: str) -> None:
self.prompt = prompt self.prompt = prompt
self.subprompt = subprompt self.subprompt = subprompt
self.pin = pin self.pin = pin
@ -82,7 +82,11 @@ CANCELLED = object()
class PinDialog(ui.Layout): class PinDialog(ui.Layout):
def __init__( def __init__(
self, prompt: str, subprompt: str, allow_cancel: bool = True, maxlength: int = 9 self,
prompt: str,
subprompt: Optional[str],
allow_cancel: bool = True,
maxlength: int = 9,
) -> None: ) -> None:
self.maxlength = maxlength self.maxlength = maxlength
self.input = PinInput(prompt, subprompt, "") self.input = PinInput(prompt, subprompt, "")