From d84adb17e78a7a7509e16b5970f0b2a95a860039 Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Mon, 24 Jun 2024 17:55:42 +0200 Subject: [PATCH] Fix pylint and mypy for ragger tests and pytools --- pytools/gpgapp/gpgcard.py | 5 ++- tests/test_cipher.py | 8 +++-- tests/test_menus.py | 75 +++++++++++++++++++++++++++------------ tests/test_password.py | 29 ++++++++++----- tests/test_seed.py | 10 ++++-- tests/test_sign.py | 12 ++++--- tests/test_slot.py | 4 ++- tests/test_template.py | 20 ++++++----- tests/test_version.py | 17 ++++----- tests/utils.py | 4 +-- 10 files changed, 122 insertions(+), 62 deletions(-) diff --git a/pytools/gpgapp/gpgcard.py b/pytools/gpgapp/gpgcard.py index 897f5b4..ce8df05 100644 --- a/pytools/gpgapp/gpgcard.py +++ b/pytools/gpgapp/gpgcard.py @@ -1010,6 +1010,7 @@ class GPGCard() : op = KEY_OPERATIONS[action] attributes = None + b_key: int = 0 if key == KeyTypes.KEY_SIG: attributes = self.data.sig.attribute b_key = DataObject.DO_SIG_KEY @@ -1167,6 +1168,7 @@ class GPGCard() : dt = datetime.utcnow().replace(microsecond=0) bdate = int(dt.timestamp()).to_bytes(4, "big") + tag: Optional[DataObject] = None if key == KeyTypes.KEY_SIG: self.data.sig.date = dt tag = DataObject.DO_DATES_WR_SIG @@ -1176,7 +1178,8 @@ class GPGCard() : elif key == KeyTypes.KEY_DEC: self.data.dec.date = dt tag = DataObject.DO_DATES_WR_DEC - self._put_data(tag, bdate) + if tag: + self._put_data(tag, bdate) def _decode_tlv(self, tlv: bytes) -> dict: diff --git a/tests/test_cipher.py b/tests/test_cipher.py index f81088b..70ab418 100644 --- a/tests/test_cipher.py +++ b/tests/test_cipher.py @@ -7,6 +7,8 @@ This module provides Ragger tests for Cipher feature from Crypto.Random import get_random_bytes from Crypto.Cipher import PKCS1_v1_5 +from ragger.backend import BackendInterface + from application_client.command_sender import CommandSender from application_client.app_def import Errors, DataObject, PassWord @@ -14,7 +16,7 @@ from utils import check_pincode, generate_key, get_RSA_pub_key # In this test we check the symmetric key encryption -def test_AES(backend): +def test_AES(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -42,7 +44,7 @@ def test_AES(backend): # In this test we check the symmetric key encryption -def test_Asym(backend): +def test_Asym(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -68,7 +70,7 @@ def test_Asym(backend): # In this test we check the symmetric key encryption with MSE -def test_MSE(backend): +def test_MSE(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) diff --git a/tests/test_menus.py b/tests/test_menus.py index 7b29162..128d7ae 100644 --- a/tests/test_menus.py +++ b/tests/test_menus.py @@ -1,5 +1,9 @@ +from typing import Sequence import pytest -from ragger.navigator import NavInsID, NavIns +from ragger.backend import BackendInterface +from ragger.firmware import Firmware +from ragger.navigator import Navigator, NavInsID, NavIns +from ragger.navigator.navigator import InstructionType from application_client.command_sender import CommandSender from application_client.app_def import PassWord @@ -11,7 +15,7 @@ from utils import ROOT_SCREENSHOT_PATH # In this test we check the behavior of the Slot menu # The Navigations go and check: # - Select slot / Slot 2 / (next page) / Set default -def test_menu_slot(firmware, backend, navigator, test_name): +def test_menu_slot(firmware: Firmware, backend: BackendInterface, navigator: Navigator, test_name: str) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -24,7 +28,8 @@ def test_menu_slot(firmware, backend, navigator, test_name): pytest.skip("single slot configuration") # Navigate in the main menu - if firmware.device.startswith("nano"): + instructions: Sequence[InstructionType] + if firmware.is_nano: initial_instructions = [ NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, # Select slot @@ -40,6 +45,7 @@ def test_menu_slot(firmware, backend, navigator, test_name): NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, # (Back) ] + else: initial_instructions = [ NavInsID.USE_CASE_CHOICE_CONFIRM, # Slots @@ -68,9 +74,10 @@ def test_menu_slot(firmware, backend, navigator, test_name): # UIF / Enable UIF for Signature # (back) # Reset / Long press 'Yes' -def test_menu_settings(firmware, backend, navigator, test_name): +def test_menu_settings(firmware: Firmware, backend: BackendInterface, navigator: Navigator, test_name: str) -> None: # Navigate in the main menu - if firmware.device == "nanos": + instructions: Sequence[InstructionType] + if firmware == Firmware.NANOS: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -144,7 +151,7 @@ def test_menu_settings(firmware, backend, navigator, test_name): NavInsID.BOTH_CLICK, # Validate ] - elif firmware.device.startswith("nano"): + elif firmware.is_nano: initial_instructions = [ NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, @@ -198,27 +205,49 @@ def test_menu_settings(firmware, backend, navigator, test_name): NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, # Validate ] + else: initial_instructions = [ NavInsID.USE_CASE_HOME_SETTINGS, # Settings ] - instructions = [ - NavIns(NavInsID.TOUCH, (350, 130)), # Key Template - NavIns(NavInsID.TOUCH, (350, 300)), # Decryption - NavIns(NavInsID.TOUCH, (350, 390)), # SECP 256K1 - NavInsID.NAVIGATION_HEADER_TAP, # (Back) - NavIns(NavInsID.TOUCH, (350, 220)), # Seed mode - NavInsID.NAVIGATION_HEADER_TAP, # (Back) - NavIns(NavInsID.TOUCH, (350, 300)), # PIN mode - NavIns(NavInsID.TOUCH, (350, 130)), # On Screen - NavInsID.CENTERED_FOOTER_TAP, # Set default - NavInsID.NAVIGATION_HEADER_TAP, # (Back) - NavIns(NavInsID.TOUCH, (350, 390)), # UIF - NavIns(NavInsID.TOUCH, (350, 130)), # UIF for Signature - NavInsID.NAVIGATION_HEADER_TAP, # (Back) - NavIns(NavInsID.TOUCH, (350, 480)), # Reset - NavInsID.USE_CASE_REVIEW_CONFIRM, # Long press 'Yes' - ] + if firmware == Firmware.STAX: + instructions = [ + NavIns(NavInsID.TOUCH, (350, 130)), # Key Template + NavIns(NavInsID.TOUCH, (350, 300)), # Decryption + NavIns(NavInsID.TOUCH, (350, 390)), # SECP 256K1 + NavInsID.NAVIGATION_HEADER_TAP, # (Back) + NavIns(NavInsID.TOUCH, (350, 220)), # Seed mode + NavInsID.NAVIGATION_HEADER_TAP, # (Back) + NavIns(NavInsID.TOUCH, (350, 300)), # PIN mode + NavIns(NavInsID.TOUCH, (350, 130)), # On Screen + NavInsID.CENTERED_FOOTER_TAP, # Set default + NavInsID.NAVIGATION_HEADER_TAP, # (Back) + NavIns(NavInsID.TOUCH, (350, 390)), # UIF + NavIns(NavInsID.TOUCH, (350, 130)), # UIF for Signature + NavInsID.NAVIGATION_HEADER_TAP, # (Back) + NavIns(NavInsID.TOUCH, (350, 480)), # Reset + NavInsID.USE_CASE_CHOICE_CONFIRM, # Press 'Reset' + ] + + else: + instructions = [ + NavIns(NavInsID.TOUCH, (430, 130)), # Key Template + NavIns(NavInsID.TOUCH, (430, 280)), # Decryption + NavIns(NavInsID.TOUCH, (430, 320)), # SECP 256K1 + NavInsID.NAVIGATION_HEADER_TAP, # (Back) + NavIns(NavInsID.TOUCH, (430, 230)), # Seed mode + NavInsID.NAVIGATION_HEADER_TAP, # (Back) + NavIns(NavInsID.TOUCH, (430, 325)), # PIN mode + NavIns(NavInsID.TOUCH, (430, 140)), # On Screen + NavInsID.EXIT_FOOTER_TAP, # Set default + NavInsID.NAVIGATION_HEADER_TAP, # (Back) + NavIns(NavInsID.TOUCH, (430, 420)), # UIF + NavIns(NavInsID.TOUCH, (430, 130)), # UIF for Signature + NavInsID.NAVIGATION_HEADER_TAP, # (Back) + NavInsID.USE_CASE_SETTINGS_NEXT, # Next page + NavIns(NavInsID.TOUCH, (430, 130)), # Reset + NavInsID.USE_CASE_CHOICE_CONFIRM, # Press 'Reset' + ] # Use the app interface instead of raw interface client = CommandSender(backend) diff --git a/tests/test_password.py b/tests/test_password.py index c115602..92da47c 100644 --- a/tests/test_password.py +++ b/tests/test_password.py @@ -4,11 +4,16 @@ """ This module provides Ragger tests for Password feature """ +from pathlib import Path import pytest +from ragger.error import ExceptionRAPDU +from ragger.backend import BackendInterface +from ragger.firmware import Firmware +from ragger.navigator import Navigator + from application_client.command_sender import CommandSender from application_client.app_def import Errors, PassWord -from ragger.error import ExceptionRAPDU from utils import util_navigate @@ -22,7 +27,7 @@ from utils import util_navigate (PassWord.PW3, "12345678"), ], ) -def test_verify(backend, pwd, value): +def test_verify(backend: BackendInterface, pwd: PassWord, value: str) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -49,7 +54,7 @@ def test_verify(backend, pwd, value): assert err.value.status & 0xFFF0 == 0x63c0 -def test_verify_wrong(backend): +def test_verify_wrong(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -60,7 +65,10 @@ def test_verify_wrong(backend): # In this test we check the card Password verification with Pinpad -def test_verify_confirm_accepted(firmware, backend, navigator, test_name): +def test_verify_confirm_accepted(firmware: Firmware, + backend: BackendInterface, + navigator: Navigator, + test_name: Path) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -70,11 +78,14 @@ def test_verify_confirm_accepted(firmware, backend, navigator, test_name): # Check the status (Asynchronous) response = client.get_async_response() - assert response.status == Errors.SW_OK + assert response and response.status == Errors.SW_OK # In this test we check the Rejected card Password verification with Pinpad -def test_verify_confirm_refused(firmware, backend, navigator, test_name): +def test_verify_confirm_refused(firmware: Firmware, + backend: BackendInterface, + navigator: Navigator, + test_name: Path) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -96,7 +107,7 @@ def test_verify_confirm_refused(firmware, backend, navigator, test_name): (PassWord.PW3, "12345678", "87654321"), ], ) -def test_change(backend, pwd, actual, new): +def test_change(backend: BackendInterface, pwd: PassWord, actual: str, new: str) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -114,7 +125,7 @@ def test_change(backend, pwd, actual, new): # In this test we check the Password Reset -def test_reset(backend): +def test_reset(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -136,7 +147,7 @@ def test_reset(backend): # In this test we check the Get Challenge -def test_challenge(backend): +def test_challenge(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) diff --git a/tests/test_seed.py b/tests/test_seed.py index 987bf67..2a7164a 100644 --- a/tests/test_seed.py +++ b/tests/test_seed.py @@ -5,8 +5,14 @@ This module provides Ragger tests for Signing feature with SEED mode """ import sys +from typing import Union import pytest +from Crypto.PublicKey.RSA import RsaKey +from Crypto.PublicKey.ECC import EccKey + +from ragger.backend import BackendInterface + from application_client.command_sender import CommandSender from application_client.app_def import Errors, DataObject, PassWord, PubkeyAlgo @@ -14,7 +20,7 @@ from utils import get_RSA_pub_key, get_ECDSA_pub_key, get_EDDSA_pub_key from utils import check_pincode, generate_key, get_key_attributes, KEY_TEMPLATES -def _gen_key(client: CommandSender, template: str): +def _gen_key(client: CommandSender, template: str) -> Union[RsaKey,EccKey]: # Verify PW3 (Admin) check_pincode(client, PassWord.PW3) @@ -50,7 +56,7 @@ def _gen_key(client: CommandSender, template: str): # "cv25519", # ECDH, SDK returns CX_EC_INVALID_CURVE ], ) -def test_seed_key(backend, template): +def test_seed_key(backend: BackendInterface, template: str) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) diff --git a/tests/test_sign.py b/tests/test_sign.py index 41ec111..ea465f5 100644 --- a/tests/test_sign.py +++ b/tests/test_sign.py @@ -9,6 +9,8 @@ from Crypto.PublicKey.RSA import RsaKey from Crypto.Signature import pkcs1_15 from Crypto.Random import get_random_bytes +from ragger.backend import BackendInterface + from application_client.command_sender import CommandSender from application_client.app_def import Errors, DataObject, PassWord, PubkeyAlgo @@ -16,7 +18,7 @@ from utils import check_pincode, get_key_attributes, get_RSA_pub_key, generate_k # In this test we check the key pair generation -def test_sign(backend): +def test_sign(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -43,7 +45,7 @@ def test_sign(backend): # In this test we check the key pair generation -def test_auth(backend): +def test_auth(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -63,8 +65,10 @@ def test_auth(backend): _verify_signature(client, hash_obj, DataObject.DO_AUT_KEY, rapdu.data) -def _verify_signature(client: CommandSender, hash_obj: SHA256.SHA256Hash, key_tag: DataObject, signature: bytes): - +def _verify_signature(client: CommandSender, + hash_obj: SHA256.SHA256Hash, + key_tag: DataObject, + signature: bytes) -> None: # Read the SIG pub Key pubkey: RsaKey = get_RSA_pub_key(client, key_tag) # Verify the signature diff --git a/tests/test_slot.py b/tests/test_slot.py index aff7eec..7778c1b 100644 --- a/tests/test_slot.py +++ b/tests/test_slot.py @@ -6,12 +6,14 @@ This module provides Ragger tests for Slots feature """ import pytest +from ragger.backend import BackendInterface + from application_client.command_sender import CommandSender from application_client.app_def import Errors, DataObject, PassWord from utils import check_pincode, generate_key -def test_slot(backend): +def test_slot(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) diff --git a/tests/test_template.py b/tests/test_template.py index 63325ab..a96170d 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -11,6 +11,8 @@ from Crypto.Signature import pkcs1_15, eddsa from Crypto.Random import get_random_bytes from Crypto.Signature import DSS +from ragger.backend import BackendInterface + from application_client.command_sender import CommandSender from application_client.app_def import Errors, DataObject, PassWord, PubkeyAlgo @@ -30,7 +32,7 @@ from utils import KEY_TEMPLATES, SHA256_DIGEST_INFO # "cv25519", # ECDH, SDK returns CX_EC_INVALID_CURVE ], ) -def test_sign(backend, template): +def test_sign(backend: BackendInterface, template: str) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -67,16 +69,16 @@ def test_sign(backend, template): # Read the SIG pub Key and Verify the signature if key_algo == PubkeyAlgo.RSA: - pubkey = get_RSA_pub_key(client, DataObject.DO_SIG_KEY) - verifier = pkcs1_15.new(pubkey) - verifier.verify(hash_obj, rapdu.data) + pubRsakey = get_RSA_pub_key(client, DataObject.DO_SIG_KEY) + rsaVerifier = pkcs1_15.new(pubRsakey) + rsaVerifier.verify(hash_obj, rapdu.data) elif key_algo == PubkeyAlgo.ECDSA: - pubkey = get_ECDSA_pub_key(client, DataObject.DO_SIG_KEY) - verifier = DSS.new(pubkey, 'fips-186-3') + pubEcckey = get_ECDSA_pub_key(client, DataObject.DO_SIG_KEY) + verifier = DSS.new(pubEcckey, 'fips-186-3') verifier.verify(hash_obj, rapdu.data[2:]) elif key_algo == PubkeyAlgo.EDDSA: - pubkey = get_EDDSA_pub_key(client, DataObject.DO_SIG_KEY) - verifier = eddsa.new(pubkey, 'rfc8032') - verifier.verify(plain, rapdu.data) + pubEcckey = get_EDDSA_pub_key(client, DataObject.DO_SIG_KEY) + eddsaVerifier = eddsa.new(pubEcckey, 'rfc8032') + eddsaVerifier.verify(plain, rapdu.data) else: raise ValueError diff --git a/tests/test_version.py b/tests/test_version.py index 45ddc3c..3af0d98 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -4,17 +4,18 @@ """ This module provides Ragger tests for Version check """ +from ragger.utils.misc import get_current_app_name_and_version +from ragger.backend import BackendInterface + from application_client.command_sender import CommandSender from application_client.app_def import Errors, DataObject, PassWord from application_client.response_unpacker import unpack_info_response -from ragger.utils.misc import get_current_app_name_and_version - from utils import verify_name, verify_version, decode_tlv, check_pincode # In this test we check the App name and version -def test_check_version(backend): +def test_check_version(backend: BackendInterface) -> None: """Check version and name""" # Send the APDU @@ -26,7 +27,7 @@ def test_check_version(backend): # In this test we check the Card activation -def test_activate(backend): +def test_activate(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -36,7 +37,7 @@ def test_activate(backend): # In this test we get the Card Application ID value -def test_info(backend): +def test_info(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -57,7 +58,7 @@ def test_info(backend): # In this test we test the User Data information -def test_user(backend): +def test_user(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = CommandSender(backend) @@ -89,7 +90,7 @@ def test_user(backend): assert rapdu.data.hex()[20:28] == serial -def _check_card_value(client, tag: DataObject, value: str): +def _check_card_value(client: CommandSender, tag: DataObject, value: str) -> None: rapdu = client.put_data(tag, value.encode("utf-8")) assert rapdu.status == Errors.SW_OK @@ -101,7 +102,7 @@ def _check_card_value(client, tag: DataObject, value: str): assert rvalue == value -def _check_user_value(client, tag: DataObject, value: str): +def _check_user_value(client: CommandSender, tag: DataObject, value: str) -> None: rapdu = client.put_data(tag, value.encode("utf-8")) assert rapdu.status == Errors.SW_OK diff --git a/tests/utils.py b/tests/utils.py index 5d5e770..4b246da 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -43,7 +43,7 @@ def util_navigate( assert text valid_instr: list[NavIns | NavInsID] = [] - if firmware.device == "nanos": + if firmware == Firmware.NANOS: text, txt_cfg = text.split("_") nav_inst = NavInsID.RIGHT_CLICK if txt_cfg == "Yes": @@ -53,7 +53,7 @@ def util_navigate( else: raise ValueError(f'Wrong text "{text}"') - elif firmware.device.startswith("nano"): + elif firmware.is_nano: text = text.split("_")[1] nav_inst = NavInsID.RIGHT_CLICK valid_instr.append(NavInsID.BOTH_CLICK)