diff --git a/tools/pico-hsm-tool.py b/tools/pico-hsm-tool.py index bc7a649..326d82b 100755 --- a/tools/pico-hsm-tool.py +++ b/tools/pico-hsm-tool.py @@ -34,6 +34,8 @@ from binascii import hexlify import sys import argparse import os +from datetime import datetime +from argparse import RawTextHelpFormatter class APDUResponse(Exception): def __init__(self, sw1, sw2): @@ -42,15 +44,19 @@ class APDUResponse(Exception): super().__init__(f'SW:{sw1:02X}{sw2:02X}') -def send_apdu(card, command, p1, p2, data): - lc = [0x00] + list(len(data).to_bytes(2, 'big')) +def send_apdu(card, command, p1, p2, data=None): + lc = [] + dataf = [] + if (data): + lc = [0x00] + list(len(data).to_bytes(2, 'big')) + dataf = data le = [0x00, 0x00] if (isinstance(command, list) and len(command) > 1): apdu = command else: apdu = [0x00, command] - apdu = apdu + [p1, p2] + lc + data + le + apdu = apdu + [p1, p2] + lc + dataf + le response, sw1, sw2 = card.connection.transmit(apdu) if (sw1 != 0x90): raise APDUResponse(sw1, sw2) @@ -73,6 +79,15 @@ def parse_args(): parser_pki_init.add_argument('--certs-dir', help='Store the PKI certificates into this directory.', default='certs') parser_pki_init.add_argument('--default', help='Setups the default public PKI from public Pico HSM PKI.', action='store_true') parser_pki_init.add_argument('--force', help='Forces the download of certificates.', action='store_true') + + parser_rtc = subparser.add_parser('datetime', help='Datetime operations with the integrated Real Time Clock (RTC).') + parser_rtc.add_argument('subcommand', choices=['set', 'get'], help='Sets or gets current datetime.') + + parser_opts = subparser.add_parser('options', help='Manage extra options.', formatter_class=RawTextHelpFormatter) + parser_opts.add_argument('subcommand', choices=['set', 'get'], help='Sets or gets option OPT.') + parser_opts.add_argument('opt', choices=['button', 'counter'], help='Button: press-to-confirm button.\nCounter: every generated key has an internal counter.') + parser_opts.add_argument('onoff', choices=['on', 'off'], help='Toggles state ON or OFF', metavar='ON/OFF', nargs='?') + args = parser.parse_args() return args @@ -213,6 +228,31 @@ def attestate(card, args): else: print(f'Key {kid} is NOT generated by device {chr.decode()}') +def rtc(card, args): + if (args.subcommand == 'set'): + now = datetime.now() + _ = send_apdu(card, [0x80, 0x64], 0x0A, 0x00, list(now.year.to_bytes(2, 'big')) + [now.month, now.day, now.weekday(), now.hour, now.minute, now.second ]) + elif (args.subcommand == 'get'): + response = send_apdu(card, [0x80, 0x64], 0x0A, 0x00) + dt = datetime(int.from_bytes(response[:2], 'big'), response[2], response[3], response[5], response[6], response[7]) + print(f'Current date and time is: {dt.ctime()}') + +def opts(card, args): + opt = 0x0 + if (args.opt == 'button'): + opt = 0x1 + elif (args.opt == 'counter'): + opt = 0x2 + current = send_apdu(card, [0x80, 0x64], 0x6, 0x0)[0] + if (args.subcommand == 'set'): + if (args.onoff == 'on'): + newopt = current | opt + else: + newopt = current & ~opt + send_apdu(card, [0x80, 0x64], 0x6, 0x0, [newopt]) + elif (args.subcommand == 'get'): + print(f'Option {args.opt.upper()} is {"ON" if current & opt else "OFF"}') + def main(args): print('Pico HSM Tool v1.2') print('Author: Pol Henarejos') @@ -238,6 +278,10 @@ def main(args): attestate(card, args) elif (args.command == 'pki'): pki(card, args) + elif (args.command == 'datetime'): + rtc(card, args) + elif (args.command == 'options'): + opts(card, args) def run(): args = parse_args()