Skip to content

Commit

Permalink
[tests] Adding more snapshot checks in NFC
Browse files Browse the repository at this point in the history
  • Loading branch information
lpascal-ledger committed Dec 2, 2024
1 parent 69da0de commit dd4f89e
Show file tree
Hide file tree
Showing 178 changed files with 292 additions and 292 deletions.
2 changes: 2 additions & 0 deletions src/ctap2/get_assertion/get_assertion_ui.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ static void ux_display_user_assertion(char buffer[static SELECT_ID_BUFFER_SIZE])
if (nameLength > 32) {
memcpy(buffer + 32, "...", sizeof("..."));
}
#else
UNUSED(nameLength);
#endif // HAVE_BAGL
}

Expand Down
13 changes: 3 additions & 10 deletions tests/functional/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,9 @@ def start(self):
self._device = LedgerCtapHidDevice(self.transport, self.debug)

self.ctap1 = LedgerCtap1(self._device, self.firmware, self.navigator, self.debug)
try:
self.ctap2 = LedgerCtap2(self._device, self.firmware, self.navigator,
self.ctap2_u2f_proxy, self.debug)
self.client_pin = ClientPin(self.ctap2)
except Exception:
# Can occurs if the app is build without FIDO2 features.
# Then only U2F tests can be used.
print("FIDO2 not supported")
self.ctap2 = None
self.client_pin = None
self.ctap2 = LedgerCtap2(self._device, self.firmware, self.navigator,
self.ctap2_u2f_proxy, self.debug)
self.client_pin = ClientPin(self.ctap2)

except Exception as e:
raise e
Expand Down
93 changes: 37 additions & 56 deletions tests/functional/ctap1_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
from fido2.ctap1 import Ctap1, ApduError, RegistrationData, SignatureData
from fido2.hid import CTAPHID

from .transport import TransportType
from .utils import prepare_apdu, LedgerCTAP
from .utils import prepare_apdu, LedgerCTAP, Nav


class APDU(IntEnum):
Expand Down Expand Up @@ -51,10 +50,6 @@ def __init__(self, device, firmware: Firmware, navigator: Navigator, debug: bool
Ctap1.__init__(self, device)
LedgerCTAP.__init__(self, firmware, navigator, debug)

@property
def nfc(self) -> bool:
return self.device.transport is TransportType.NFC

def parse_response(self, response):
status = struct.unpack(">H", response[-2:])[0]
try:
Expand All @@ -79,7 +74,7 @@ def send_apdu_nowait(self, cla=0, ins=0, p1=0, p2=0, data=b""):
apdu = prepare_apdu(cla=cla, ins=ins, p1=p1, p2=p2, data=data)
self.device.send(CTAPHID.MSG, apdu)

def register(self, client_param, app_param, user_accept=True,
def register(self, client_param, app_param, navigation: Nav = Nav.USER_ACCEPT,
check_screens=None, compare_args=None):
# Refresh navigator screen content reference
self.navigator._backend.get_current_screen_content()
Expand All @@ -90,29 +85,22 @@ def register(self, client_param, app_param, user_accept=True,
text = None
nav_ins = None
val_ins = None
check_navigation = (user_accept is not None or self.nfc)

if self.nfc:
check_navigation = False
else:
if self.firmware.is_nano:
nav_ins = NavInsID.RIGHT_CLICK
val_ins = [NavInsID.BOTH_CLICK]
if user_accept is not None:
if user_accept:
text = "Register"
else:
text = "Abort"
elif self.firmware in [Firmware.STAX, Firmware.FLEX]:
if user_accept is not None:
if user_accept:
val_ins = [NavInsID.USE_CASE_CHOICE_CONFIRM]
else:
val_ins = [NavInsID.USE_CASE_CHOICE_REJECT]

self.navigate(check_navigation,

if self.firmware.is_nano:
nav_ins = NavInsID.RIGHT_CLICK
val_ins = [NavInsID.BOTH_CLICK]
if navigation is Nav.USER_ACCEPT:
text = "Register"
else:
text = "Abort"
elif self.firmware in [Firmware.STAX, Firmware.FLEX]:
if navigation is Nav.USER_ACCEPT:
val_ins = [NavInsID.USE_CASE_CHOICE_CONFIRM]
else:
val_ins = [NavInsID.USE_CASE_CHOICE_REJECT]

self.navigate(navigation,
check_screens,
False, # Never check cancel
compare_args,
text,
nav_ins,
Expand All @@ -132,17 +120,17 @@ def register(self, client_param, app_param, user_accept=True,
response = self.device.recv(CTAPHID.MSG)
response = self.parse_response(response)
else:
if user_accept is not None:
if navigation is not Nav.NONE:
self.wait_for_return_on_dashboard()
raise e

if user_accept is not None:
if navigation is not Nav.NONE:
self.wait_for_return_on_dashboard()

return RegistrationData(response)

def authenticate(self, client_param, app_param, key_handle,
check_only=False, user_accept=True,
check_only=False, navigation: Nav = Nav.USER_ACCEPT,
check_screens=None, compare_args=None):
# Refresh navigator screen content reference
self.navigator._backend.get_current_screen_content()
Expand All @@ -155,29 +143,22 @@ def authenticate(self, client_param, app_param, key_handle,
text = None
nav_ins = None
val_ins = None
check_navigation = (user_accept is not None or self.nfc)

if self.nfc:
check_navigation = False
else:
if self.firmware.is_nano:
nav_ins = NavInsID.RIGHT_CLICK
val_ins = [NavInsID.BOTH_CLICK]
if user_accept is not None:
if user_accept:
text = "Login"
else:
text = "Abort"
elif self.firmware in [Firmware.STAX, Firmware.FLEX]:
if user_accept is not None:
if user_accept:
val_ins = [NavInsID.USE_CASE_CHOICE_CONFIRM]
else:
val_ins = [NavInsID.USE_CASE_CHOICE_REJECT]

self.navigate(check_navigation,

if self.firmware.is_nano:
nav_ins = NavInsID.RIGHT_CLICK
val_ins = [NavInsID.BOTH_CLICK]
if navigation is Nav.USER_ACCEPT:
text = "Login"
else:
text = "Abort"
elif self.firmware in [Firmware.STAX, Firmware.FLEX]:
if navigation is Nav.USER_ACCEPT:
val_ins = [NavInsID.USE_CASE_CHOICE_CONFIRM]
else:
val_ins = [NavInsID.USE_CASE_CHOICE_REJECT]

self.navigate(navigation,
check_screens,
False, # Never check cancel
compare_args,
text,
nav_ins,
Expand All @@ -198,11 +179,11 @@ def authenticate(self, client_param, app_param, key_handle,
response = self.device.recv(CTAPHID.MSG)
response = self.parse_response(response)
else:
if user_accept is not None:
if navigation is not Nav.NONE:
self.wait_for_return_on_dashboard()
raise e

if user_accept is not None:
if navigation is not Nav.NONE:
self.wait_for_return_on_dashboard()

return SignatureData(response)
22 changes: 11 additions & 11 deletions tests/functional/ctap2/test_client_pin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from fido2.webauthn import AttestedCredentialData, AuthenticatorData

from ..utils import generate_random_bytes, generate_make_credentials_params, \
ctap2_get_assertion
ctap2_get_assertion, Nav


PIN_A = "aaaa"
Expand Down Expand Up @@ -51,7 +51,7 @@ def test_client_pin_check_not_set(client):
# Impact is minor because user as still manually unlocked it's device.
# therefore user presence is somehow guarantee.
with pytest.raises(CtapError) as e:
client.ctap2.make_credential(args, user_accept=None, will_fail=True)
client.ctap2.make_credential(args, navigation=Nav.NONE, will_fail=True)
assert e.value.code == CtapError.ERR.PIN_NOT_SET

# Check get assertion request behavior with zero length pinAuth
Expand All @@ -69,7 +69,7 @@ def test_client_pin_check_not_set(client):
allow_list,
pin_uv_param=b"",
pin_uv_protocol=client.client_pin.protocol.VERSION,
user_accept=None,
navigation=Nav.NONE,
will_fail=True)
assert e.value.code == CtapError.ERR.PIN_NOT_SET

Expand Down Expand Up @@ -105,7 +105,7 @@ def test_client_pin_check_set(client):
# Impact is minor because user as still manually unlocked it's device.
# therefore user presence is somehow guarantee.
with pytest.raises(CtapError) as e:
client.ctap2.make_credential(args, user_accept=None, will_fail=True)
client.ctap2.make_credential(args, navigation=Nav.NONE, will_fail=True)
assert e.value.code == CtapError.ERR.PIN_INVALID

# Check get assertion request behavior with zero length pinAuth
Expand All @@ -124,7 +124,7 @@ def test_client_pin_check_set(client):
allow_list,
pin_uv_param=b"",
pin_uv_protocol=client.client_pin.protocol.VERSION,
user_accept=None,
navigation=Nav.NONE,
will_fail=True)
assert e.value.code == CtapError.ERR.PIN_INVALID

Expand Down Expand Up @@ -153,21 +153,21 @@ def test_use_pin(client):

# Check should use pin
with pytest.raises(CtapError) as e:
client.ctap2.make_credential(args, user_accept=None, will_fail=True)
client.ctap2.make_credential(args, navigation=Nav.NONE, will_fail=True)
assert e.value.code == CtapError.ERR.PUAT_REQUIRED

# Check should use correct token
with pytest.raises(CtapError) as e:
args.pin_uv_param = bad_pin_auth
args.pin_uv_protocol = client.client_pin.protocol.VERSION
client.ctap2.make_credential(args, user_accept=None)
client.ctap2.make_credential(args, navigation=Nav.NONE)
assert e.value.code == CtapError.ERR.PIN_AUTH_INVALID

# Check should use correct protocol
with pytest.raises(CtapError) as e:
args.pin_uv_param = pin_auth
args.pin_uv_protocol = PinProtocolV2.VERSION
client.ctap2.make_credential(args, user_accept=None)
client.ctap2.make_credential(args, navigation=Nav.NONE)
assert e.value.code == CtapError.ERR.PIN_AUTH_INVALID

# Using a bad token doesn't affect pin_retries
Expand Down Expand Up @@ -195,15 +195,15 @@ def test_use_pin(client):
client.ctap2.get_assertion(args.rp["id"], client_data_hash, allow_list,
pin_uv_param=bad_pin_auth,
pin_uv_protocol=client.client_pin.protocol.VERSION,
user_accept=None)
navigation=Nav.NONE)
assert e.value.code == CtapError.ERR.PIN_AUTH_INVALID

# Check should use correct protocol
with pytest.raises(CtapError) as e:
client.ctap2.get_assertion(args.rp["id"], client_data_hash, allow_list,
pin_uv_param=pin_auth,
pin_uv_protocol=PinProtocolV2.VERSION,
user_accept=None)
navigation=Nav.NONE)
assert e.value.code == CtapError.ERR.PIN_AUTH_INVALID

# Check with pin
Expand Down Expand Up @@ -243,7 +243,7 @@ def test_client_pin_unique_token(client):
args = generate_make_credentials_params(client, pin_uv_param=b"")
args.pin_uv_param = client.client_pin.protocol.authenticate(token_a, args.client_data_hash)
with pytest.raises(CtapError) as e:
client.ctap2.make_credential(args, user_accept=None)
client.ctap2.make_credential(args, navigation=Nav.NONE)
assert e.value.code == CtapError.ERR.PIN_AUTH_INVALID

# Check that second token can be used to validate the same request
Expand Down
1 change: 0 additions & 1 deletion tests/functional/ctap2/test_extension_hmac_secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ def test_extensions_hmac_secret_error(client):
client.ctap2.get_assertion(args.rp["id"],
args.client_data_hash,
allow_list,
will_fail=True,
extensions=extensions)
# TODO: understand why this sometimes (quite often actually) raises
# INVALID_CBOR instead of the expected MISSING_PARAMETER
Expand Down
5 changes: 2 additions & 3 deletions tests/functional/ctap2/test_fido2_screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def register_then_assert(client, test_name, user):
args.user = user
compare_args = (TESTS_SPECULOS_DIR, client.transported_path(test_name) + "/make")
attestation = client.ctap2.make_credential(args,
check_screens="fast",
check_screens=True,
compare_args=compare_args)
credential_data = AttestedCredentialData(attestation.auth_data.credential_data)

Expand All @@ -78,9 +78,8 @@ def register_then_assert(client, test_name, user):
allow_list = [{"id": credential_data.credential_id, "type": "public-key"}]
compare_args = (TESTS_SPECULOS_DIR, client.transported_path(test_name) + "/get")
assertion = client.ctap2.get_assertion(args.rp["id"], client_data_hash, allow_list,
user_accept=True,
check_users=[args.user],
check_screens="fast",
check_screens=True,
compare_args=compare_args)

assertion.verify(client_data_hash, credential_data.public_key)
Expand Down
Loading

0 comments on commit dd4f89e

Please sign in to comment.