From 546523ad43c13761746fe72204822bc47b358e8b Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Thu, 14 Mar 2024 08:53:34 +0100 Subject: [PATCH] Improve test tools - Replace 'pycard' by 'ledgercomm', allowint to work also with 'speculos' - Update 'manual-tests' allowing expert mode init with full log generation - Improve backup meachnism - Add 'seed-key' option directly to 'backup.py' for easier operation - Adapt the document accordingly --- doc/user/app-openpgp.pdf | Bin 1217897 -> 1217912 bytes doc/user/app-openpgp.rst | 8 ++++---- manual-tests/manual.sh | 10 ++++++++++ pytools/backup.py | 9 ++++++++- pytools/gpgapp/gpgcard.py | 29 ++++++++++++----------------- pytools/gpgcli.py | 2 +- pytools/requirements.txt | 2 +- 7 files changed, 36 insertions(+), 24 deletions(-) diff --git a/doc/user/app-openpgp.pdf b/doc/user/app-openpgp.pdf index ccab45b3b4bb49680a2fcb672da048603b827efb..5e2ea57d2c0731c9d915712a811425527a5456f1 100644 GIT binary patch delta 5363 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 Cd`%Ys delta 5337 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 diff --git a/doc/user/app-openpgp.rst b/doc/user/app-openpgp.rst index d665220..48ac27d 100644 --- a/doc/user/app-openpgp.rst +++ b/doc/user/app-openpgp.rst @@ -1562,6 +1562,7 @@ The tool usage is the following: | ``--user-pin PIN User PIN (if pinpad not used)`` | ``--restore Perform a Restore instead of Backup`` | ``--file FILE Backup/Restore file (default is 'gpg_backup')`` + | ``--seed-key After Restore, regenerate all keys, based on seed mode`` | | ``Keys restore is only possible with SEED mode...`` @@ -1571,12 +1572,11 @@ To perform a backup, simply use the tool like this: | ``Connect to card 'Ledger'...`` | ``Configuration saved in file 'gpg_backup'.`` -Once the configuration is restored, just use the previous tool to re-generate the seeded keys: +To *restore* a backup, simply use the tool like this: - | ``./gpgcli.py --user-pin 123456 --adm-pin 12345678 --seed-key`` + | ``$ ./backup.py --restore --adm-pin 12345678 --user-pin 123456 --seed-key`` | ``Connect to card 'Ledger'...`` - | ``Verify PINs...`` - | ``Get card info...`` + | ``Configuration saved in file 'gpg_backup'.`` Annexes ======= diff --git a/manual-tests/manual.sh b/manual-tests/manual.sh index d882da9..082cd9b 100755 --- a/manual-tests/manual.sh +++ b/manual-tests/manual.sh @@ -62,6 +62,16 @@ init() { echo enable-pinpad-varlen echo card-timeout 1 } > "${dir}/scdaemon.conf" + + if [[ ${EXPERT} == true ]]; then + { + echo log-file /tmp/scd.log + echo debug-level guru + echo debug-all + } >> "${dir}/scdaemon.conf" + fi + + gpgconf --reload scdaemon } #=============================================================================== diff --git a/pytools/backup.py b/pytools/backup.py index bdf7268..9a4e66e 100755 --- a/pytools/backup.py +++ b/pytools/backup.py @@ -34,7 +34,7 @@ def get_argparser() -> Namespace: formatter_class=RawTextHelpFormatter ) parser.add_argument("--reader", type=str, default="Ledger", - help="PCSC reader name (default is '%(default)s')") + help="PCSC reader name (default is '%(default)s') or 'speculos'") parser.add_argument("--slot", type=int, choices=range(1, 4), help="Select slot (1 to 3)") @@ -51,6 +51,9 @@ def get_argparser() -> Namespace: parser.add_argument("--file", type=str, default="gpg_backup", help="Backup/Restore file (default is '%(default)s')") + parser.add_argument("--seed-key", action="store_true", + help="After Restore, regenerate all keys, based on seed mode") + return parser.parse_args() @@ -95,6 +98,10 @@ def entrypoint() -> None: if args.restore: gpgcard.restore(args.file) print(f"Configuration restored from file '{args.file}'.") + + if args.seed_key: + gpgcard.seed_key() + else: gpgcard.backup(args.file) print(f"Configuration saved in file '{args.file}'.") diff --git a/pytools/gpgapp/gpgcard.py b/pytools/gpgapp/gpgcard.py index 665a353..9e08884 100644 --- a/pytools/gpgapp/gpgcard.py +++ b/pytools/gpgapp/gpgcard.py @@ -24,14 +24,12 @@ from dataclasses import dataclass from Crypto.PublicKey.RSA import construct -# pylint: disable=import-error -from smartcard.System import readers # type: ignore -from smartcard.pcsc import PCSCReader # type: ignore -from smartcard import CardConnectionDecorator # 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 @@ -143,7 +141,7 @@ def reset(self): class GPGCard() : def __init__(self) -> None: self.log: bool = False - self.connection: CardConnectionDecorator = None + self.transport: Transport = None self.slot_current: bytes = b"\x00" self.slot_config: bytes = bytes(3) self.data: CardInfo = CardInfo() @@ -156,21 +154,17 @@ def connect(self, device: str) -> None: device (str): Reader device name """ - allreaders: list = readers() - for elt in allreaders: - if str(elt).startswith(device): - reader: PCSCReader.PCSCReader = elt - self.connection = reader.createConnection() - self.connection.connect() - return + if device == "speculos": + self.transport = Transport("tcp", server="127.0.0.1", port=9999, debug=False) + else: + self.transport = Transport("hid") print("") - raise GPGCardExcpetion(ErrorCodes.ERR_INTERNAL, "No Reader detected!") def disconnect(self): """Connect from the selected Reader""" - return self.connection.disconnect() + self.transport.close() ############### LOG interface ############### @@ -1236,8 +1230,9 @@ def _transmit(self, data: bytes, long_resp: bool = False) -> Tuple[bytes, int, i """ self.add_log("send", data) - resp, sw1, sw2 = self.connection.transmit(list(data)) - sw = (sw1 << 8) | sw2 + sw, resp = self.transport.exchange_raw(data) + sw1 = (sw >> 8) & 0xFF + sw2 = sw & 0xFF self.add_log("recv", resp, sw) if sw != ErrorCodes.ERR_SUCCESS and not long_resp: raise GPGCardExcpetion(sw, "") diff --git a/pytools/gpgcli.py b/pytools/gpgcli.py index 797fb12..4d85839 100755 --- a/pytools/gpgcli.py +++ b/pytools/gpgcli.py @@ -38,7 +38,7 @@ def get_argparser() -> Namespace: parser.add_argument("--info", action="store_true", help="Get and display card information") parser.add_argument("--reader", type=str, default="Ledger", - help="PCSC reader name (default is '%(default)s')") + help="PCSC reader name (default is '%(default)s') or 'speculos'") parser.add_argument("--apdu", action="store_true", help="Log APDU exchange") parser.add_argument("--slot", type=int, choices=range(1, 4), help="Select slot (1 to 3)") diff --git a/pytools/requirements.txt b/pytools/requirements.txt index 2baafa8..0c51a3d 100644 --- a/pytools/requirements.txt +++ b/pytools/requirements.txt @@ -1,2 +1,2 @@ -pyscard pycryptodome +ledgercomm