diff --git a/.github/workflows/codeql_checks.yml b/.github/workflows/codeql_checks.yml index ff59de9c..9b559d7e 100644 --- a/.github/workflows/codeql_checks.yml +++ b/.github/workflows/codeql_checks.yml @@ -14,31 +14,6 @@ on: jobs: analyse: - name: Analyse - strategy: - fail-fast: false - matrix: - sdk: ["$NANOX_SDK", "$NANOSP_SDK", "$STAX_SDK", "$FLEX_SDK", "$APEX_P_SDK"] - # 'cpp' covers C and C++ - language: ['cpp'] - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest - - steps: - - name: Clone - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - queries: security-and-quality - - # CodeQL will create the database during the compilation - - name: Build - run: | - make BOLOS_SDK=${{ matrix.sdk }} - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + name: Call Ledger CodeQL analysis + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_codeql_checks.yml@v1 + secrets: inherit diff --git a/.github/workflows/python_client_checks.yml b/.github/workflows/python_client_checks.yml index e86f3d4b..3640fd55 100644 --- a/.github/workflows/python_client_checks.yml +++ b/.github/workflows/python_client_checks.yml @@ -14,27 +14,11 @@ on: jobs: lint: - name: Client linting - runs-on: ubuntu-latest - steps: - - name: Clone - uses: actions/checkout@v4 - - name: Installing PIP dependencies - run: | - pip install pylint - pip install -r tests/ragger/requirements.txt - - name: Lint Python code - run: pylint --rc tests/ragger/setup.cfg tests/ragger/application_client/ - - mypy: - name: Type checking - runs-on: ubuntu-latest - steps: - - name: Clone - uses: actions/checkout@v4 - - name: Installing PIP dependencies - run: | - pip install mypy - pip install -r tests/ragger/requirements.txt - - name: Mypy type checking - run: mypy tests/ragger/application_client/ + name: Call Ledger Python linters + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_python_checks.yml@v1 + with: + run_linter: pylint + run_type_check: true + src_directory: application_client + setup_directory: tests/ragger + req_directory: tests/ragger diff --git a/.github/workflows/python_tool_checks.yml b/.github/workflows/python_tool_checks.yml index 01d31c84..2c948b91 100644 --- a/.github/workflows/python_tool_checks.yml +++ b/.github/workflows/python_tool_checks.yml @@ -14,29 +14,12 @@ on: jobs: lint: - name: Client linting - runs-on: ubuntu-latest - steps: - - name: Clone - uses: actions/checkout@v4 - - name: Installing PIP dependencies - run: | - sudo apt-get update && sudo apt-get install -y libpcsclite-dev - pip install pylint - pip install -r pytools/requirements.txt - - name: Lint Python code - run: pylint --rc pytools/setup.cfg pytools/ - - mypy: - name: Type checking - runs-on: ubuntu-latest - steps: - - name: Clone - uses: actions/checkout@v4 - - name: Installing PIP dependencies - run: | - sudo apt-get update && sudo apt-get install -y libpcsclite-dev - pip install mypy - pip install -r pytools/requirements.txt - - name: Mypy type checking - run: mypy pytools/ + name: Call Ledger Python linters + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_python_checks.yml@v1 + with: + run_linter: pylint + run_type_check: true + src_directory: . + setup_directory: pytools + req_directory: pytools + additional_packages: libpcsclite-dev diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 3dd30a67..acacc350 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -10,49 +10,8 @@ on: jobs: job_unit_test: - name: Unit test - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest - - steps: - - name: Clone - uses: actions/checkout@v4 - - - name: Build unit tests - run: | - cd tests/unit - cmake -Bbuild -H. && make -C build - - - name: Run the tests - run: | - cd tests/unit - make -C build test - - - name: Generate code coverage - run: | - cd tests/unit - lcov --directory . -b "$(realpath build/)" --capture --initial -o coverage.base - lcov --rc lcov_branch_coverage=1 --directory . -b "$(realpath build/)" --capture -o coverage.capture - lcov --directory . -b "$(realpath build/)" --add-tracefile coverage.base --add-tracefile coverage.capture -o coverage.info - lcov --directory . -b "$(realpath build/)" --remove coverage.info '*/tests/unit/*' -o coverage.info - genhtml coverage.info -o coverage - - - uses: actions/upload-artifact@v4 - with: - name: code-coverage - path: tests/unit/coverage - - - name: Install codecov dependencies - run: apt install --no-install-recommends -y curl gpg - - - name: Upload to codecov.io - uses: codecov/codecov-action@v5 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - with: - files: ./tests/unit/coverage.info - flags: unittests - name: codecov-app-openpgp - fail_ci_if_error: true - verbose: true + name: Call Ledger unit_test + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_unit_tests.yml@v1 + secrets: inherit + with: + test_directory: tests/unit diff --git a/Makefile b/Makefile index 59f7b852..c132b8e9 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ APPNAME = OpenPGP # Application version APPVERSION_M = 2 APPVERSION_N = 5 -APPVERSION_P = 0 +APPVERSION_P = 1 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" DEFINES += SPEC_VERSION='"3.3.1"' diff --git a/doc/user/0001-plist.patch b/doc/user/0001-plist-ubuntu22.patch similarity index 100% rename from doc/user/0001-plist.patch rename to doc/user/0001-plist-ubuntu22.patch diff --git a/doc/user/0001-plist-ubuntu24.patch b/doc/user/0001-plist-ubuntu24.patch new file mode 100644 index 00000000..af368843 --- /dev/null +++ b/doc/user/0001-plist-ubuntu24.patch @@ -0,0 +1,35 @@ +--- libccid_Info.plist_org 2025-09-23 10:35:20.962252106 +0200 ++++ libccid_Info.plist 2025-09-23 10:54:39.042011175 +0200 +@@ -499,6 +499,10 @@ + 0x2C97 + 0x2C97 + 0x2C97 ++ 0x2C97 ++ 0x2C97 ++ 0x2C97 ++ 0x2C97 + 0x17EF + 0x17EF + 0x17EF +@@ -1096,6 +1100,10 @@ + 0x1009 + 0x4009 + 0x5009 ++ 0x5000 ++ 0x6000 ++ 0x7000 ++ 0x8000 + 0x6007 + 0x6055 + 0x6111 +@@ -1693,6 +1701,10 @@ + Ledger Nano S + Ledger Nano X + Ledger Nano S Plus ++ Ledger Nano S Plus Legacy ++ Ledger Flex ++ Ledger Stax ++ Ledger Apex P + Lenovo Lenovo USB Smartcard Keyboard + Lenovo Lenovo USB Smartcard Keyboard + Lenovo Lenovo Smartcard Wired Keyboard II diff --git a/doc/user/app-openpgp.rst b/doc/user/app-openpgp.rst index b084a834..02dc7a5d 100644 --- a/doc/user/app-openpgp.rst +++ b/doc/user/app-openpgp.rst @@ -75,16 +75,52 @@ Linux You have to add your devices to ``/etc/libccid_Info.plist`` -MAC -~~~ +macOS +~~~~~ + +Two supported approaches: + +**A: Recommended: enable the bundled IFD CCID driver (no SIP required)** + +On recent macOS releases (Sonoma 14 and Sequoia 15), Apple ships both its own CCID driver and Ludovic Rousseau’s **IFD CCID** (included by Apple; 1.5.1 in current builds). If your Ledger is not detected or behaves oddly with the Apple driver, enable IFD CCID: + +.. code-block:: bash + + # Enable IFD CCID system-wide + sudo defaults write /Library/Preferences/com.apple.security.smartcard useIFDCCID -bool yes + +Verify the setting (``1`` means IFD CCID is enabled; “does not exist” means Apple driver is used): + +.. code-block:: bash + + defaults read /Library/Preferences/com.apple.security.smartcard.plist useIFDCCID + +To revert to the Apple driver later: + +.. code-block:: bash + + sudo defaults delete /Library/Preferences/com.apple.security.smartcard useIFDCCID + # or + sudo defaults write /Library/Preferences/com.apple.security.smartcard useIFDCCID -bool no + +Unplug/replug the device after changing the setting. A reboot is rarely necessary. + +**B: Legacy: manual device list (advanced; may require disabling SIP)** + +Only if you must maintain a custom device list for IFD CCID. Edit: + +``/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist`` -1. First it is necessary to disable SIP, that forbid editing files in ``/usr/``. -2. You have to add your devices to ``/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist`` -3. Enable SIP +.. warning:: + Editing system files may be blocked by SIP (System Integrity Protection) and is discouraged unless strictly necessary. + Prefer the single-command switch above whenever possible. -Note: See https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html +.. note:: + If you need to disable/enable SIP to edit system files, see Apple’s documentation: + https://developer.apple.com/documentation/security/disabling-and-enabling-system-integrity-protection -TBC... +See the **Manual update of CCID** section below for the required XML keys (``ifdVendorID``, ``ifdProductID``, ``ifdFriendlyName``) and Ledger device values. +We intentionally keep those details centralized in that section. Windows ~~~~~~~ diff --git a/pytools/gpgapp/gpgcard.py b/pytools/gpgapp/gpgcard.py index b436a177..abe2d5e2 100644 --- a/pytools/gpgapp/gpgcard.py +++ b/pytools/gpgapp/gpgcard.py @@ -22,15 +22,14 @@ from hashlib import sha1 from typing import Optional, Tuple from dataclasses import dataclass +# pylint: disable=import-error from Crypto.PublicKey.RSA import construct +from ledgercomm import Transport # type: ignore +# pylint: enable=import-error from gpgapp.gpgcmd import DataObject, ErrorCodes, KeyTypes, PassWord, PubkeyAlgo # type: ignore from gpgapp.gpgcmd import KEY_OPERATIONS, KEY_TEMPLATES, USER_SALUTATION # type: ignore -# pylint: disable=import-error -from ledgercomm import Transport # type: ignore -# pylint: enable=import-error - APDU_MAX_SIZE: int = 0xFE APDU_CHAINING_MODE: int = 0x10 diff --git a/src/gpg_ux_nbgl.c b/src/gpg_ux_nbgl.c index 5c752b29..269e7dc9 100644 --- a/src/gpg_ux_nbgl.c +++ b/src/gpg_ux_nbgl.c @@ -1168,12 +1168,6 @@ void ui_menu_pinconfirm_display(unsigned int value) { /* ------------------------------ PIN ENTRY UX ----------------------------- */ -// clang-format off -enum { - TOKEN_PIN_ENTRY_BACK = FIRST_USER_TOKEN, -}; -// clang-format on - static void ui_menu_pinentry_cb(void); /** @@ -1288,22 +1282,6 @@ static void pinback_cb(void) { ui_init(); } -#ifdef SCREEN_SIZE_WALLET -/** - * @brief Pin Entry Action callback - * - * @param[in] token button Id pressed - * @param[in] index widget index on the page - * - */ -static void pinentry_cb(int token, uint8_t index) { - UNUSED(index); - if (token == TOKEN_PIN_ENTRY_BACK) { - pinback_cb(); - } -} -#endif // SCREEN_SIZE_WALLET - /** * @brief Pin Entry page display * @@ -1343,23 +1321,13 @@ void ui_menu_pinentry_display(unsigned int step) { minLen = (G_gpg_vstate.io_p2 == PIN_ID_PW3) ? GPG_MIN_PW3_LENGTH : GPG_MIN_PW1_LENGTH; // Draw the keypad -#ifdef SCREEN_SIZE_WALLET - nbgl_useCaseKeypadPIN(G_gpg_vstate.menu, - minLen, - GPG_MAX_PW_LENGTH, - TOKEN_PIN_ENTRY_BACK, - false, - TUNE_TAP_CASUAL, - pinentry_validate_cb, - pinentry_cb); -#else // SCREEN_SIZE_WALLET - nbgl_useCaseKeypadPIN(G_gpg_vstate.menu, - minLen, - GPG_MAX_PW_LENGTH, - false, - pinentry_validate_cb, - pinback_cb); -#endif // SCREEN_SIZE_WALLET + nbgl_useCaseKeypad(G_gpg_vstate.menu, + minLen, + GPG_MAX_PW_LENGTH, + false, + true, + pinentry_validate_cb, + pinback_cb); } /** diff --git a/tests/ragger/snapshots/apex_p/test_menu_settings/00011.png b/tests/ragger/snapshots/apex_p/test_menu_settings/00011.png index bd6b4f30..ffaaf168 100644 Binary files a/tests/ragger/snapshots/apex_p/test_menu_settings/00011.png and b/tests/ragger/snapshots/apex_p/test_menu_settings/00011.png differ diff --git a/tests/ragger/snapshots/apex_p/test_menu_settings/00012.png b/tests/ragger/snapshots/apex_p/test_menu_settings/00012.png index 7695c425..9605256f 100644 Binary files a/tests/ragger/snapshots/apex_p/test_menu_settings/00012.png and b/tests/ragger/snapshots/apex_p/test_menu_settings/00012.png differ