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
pull/100/head
Charles-Edouard de la Vergne 3 months ago
parent 2d309b8c79
commit 546523ad43
No known key found for this signature in database
GPG Key ID: F12296941B7BB9C6

Binary file not shown.

@ -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
=======

@ -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
}
#===============================================================================

@ -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}'.")

@ -24,14 +24,12 @@ from typing import Optional, Tuple
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 @@ class CardInfo:
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 @@ class GPGCard() :
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 @@ class GPGCard() :
"""
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, "")

@ -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)")

@ -1,2 +1,2 @@
pyscard
pycryptodome
ledgercomm

Loading…
Cancel
Save