Skip to content

Commit

Permalink
Improve test tools
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
cedelavergne-ledger committed Mar 14, 2024
1 parent 2d309b8 commit 546523a
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 24 deletions.
Binary file modified doc/user/app-openpgp.pdf
Binary file not shown.
8 changes: 4 additions & 4 deletions doc/user/app-openpgp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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...``
Expand All @@ -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
=======
Expand Down
10 changes: 10 additions & 0 deletions manual-tests/manual.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

#===============================================================================
Expand Down
9 changes: 8 additions & 1 deletion pytools/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)")

Expand All @@ -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()


Expand Down Expand Up @@ -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}'.")
Expand Down
29 changes: 12 additions & 17 deletions pytools/gpgapp/gpgcard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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 ###############
Expand Down Expand Up @@ -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, "")
Expand Down
2 changes: 1 addition & 1 deletion pytools/gpgcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)")
Expand Down
2 changes: 1 addition & 1 deletion pytools/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pyscard
pycryptodome
ledgercomm

0 comments on commit 546523a

Please sign in to comment.