Now using the shell class in cyberflex-shell
git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@40 f711b948-2313-0410-aaa9-d29f33439f0b
This commit is contained in:
parent
c584dad0b0
commit
5e5b85b28e
|
@ -188,39 +188,36 @@ class Cyberflex_Card(Java_Card):
|
|||
|
||||
return result[0] == 0x0
|
||||
|
||||
def cmd_delete(self, *args):
|
||||
if len(args) != 1:
|
||||
raise TypeError, "Must have exactly one argument."
|
||||
aid = binascii.a2b_hex("".join(args[0].split()))
|
||||
def cmd_delete(self, aid):
|
||||
"""Delete the object identified by aid."""
|
||||
aid = binascii.a2b_hex("".join(aid.split()))
|
||||
self.delete(aid)
|
||||
|
||||
def cmd_status(self, *args):
|
||||
if len(args) > 1:
|
||||
raise TypeError, "Can have at most one argument."
|
||||
if len(args) == 1:
|
||||
reference_control = int(args[0], 0)
|
||||
else:
|
||||
reference_control = 0x20
|
||||
def cmd_status(self, reference_control = "0x20"):
|
||||
"""Execute a GetStatus command and return the result."""
|
||||
reference_control = int(reference_control, 0)
|
||||
result = self.get_status(reference_control)
|
||||
utils.parse_status(result[:-2])
|
||||
|
||||
def cmd_secure(self, *args):
|
||||
if len(args) == 0:
|
||||
def cmd_secure(self, keyset_version=None, key_index=None, security_level=None):
|
||||
"""Open a secure channel.
|
||||
If given, keyset_version and key_index must be integers while security_level can be one of 0, clear, 1, mac, 3, macenc, mac+enc."""
|
||||
if keyset_version is None and key_index is None and security_level is None:
|
||||
arg1 = 0
|
||||
arg2 = 0
|
||||
arg3int = SECURE_CHANNEL_MAC
|
||||
elif len(args)== 3:
|
||||
arg1 = int(args[0],0)
|
||||
arg2 = int(args[1],0)
|
||||
elif keyset_version is not None and key_index is not None and security_level is not None:
|
||||
arg1 = int(keyset_version,0)
|
||||
arg2 = int(key_index,0)
|
||||
|
||||
if arg1 not in range(256):
|
||||
raise ValueError, "keyset_version must be between 0 and 255 (inclusive)."
|
||||
if arg2 not in (0,1):
|
||||
raise ValueError, "key_index must be 0 or 1."
|
||||
|
||||
arg3 = args[2].strip().lower()
|
||||
arg3 = security_level.strip().lower()
|
||||
try:
|
||||
arg3int = int(args[2],0)
|
||||
arg3int = int(security_level,0)
|
||||
except:
|
||||
arg3int = None
|
||||
|
||||
|
@ -234,19 +231,19 @@ class Cyberflex_Card(Java_Card):
|
|||
raise TypeError, "Must give none or three arguments."
|
||||
self.open_secure_channel(arg1, arg2, arg3int)
|
||||
|
||||
def cmd_setkey(self, *args):
|
||||
if len(args) != 2:
|
||||
raise TypeError, "Need exactly two arguments: keyset index and key"
|
||||
arg1 = args[0].strip().lower()
|
||||
def cmd_setkey(self, key_index, key):
|
||||
"""Set a key in the current keyset.
|
||||
key_index should be one of 0, all, 1, enc, auth, 2, mac, 3, kek."""
|
||||
arg1 = key_index.strip().lower()
|
||||
try:
|
||||
arg1int = int(arg1,0)
|
||||
except:
|
||||
arg1int = None
|
||||
|
||||
if len(args[1]) != 16:
|
||||
arg2 = binascii.a2b_hex("".join(args[1].split()))
|
||||
if len(key) != 16:
|
||||
arg2 = binascii.a2b_hex("".join(key.split()))
|
||||
else:
|
||||
arg2 = args[1]
|
||||
arg2 = key
|
||||
|
||||
if len(arg2) != 16:
|
||||
raise TypeError, "Need either exactly 16 binary bytes or 16 hexadezimal bytes for the key argument."
|
||||
|
@ -263,27 +260,27 @@ class Cyberflex_Card(Java_Card):
|
|||
if all or arg1int == KEY_KEK or arg1 == "kek":
|
||||
self.keyset[KEY_KEK] = arg2
|
||||
|
||||
def cmd_printkeyset(self, *args):
|
||||
def cmd_printkeyset(self):
|
||||
"""Print the current keyset."""
|
||||
print "ENC,AUTH:", utils.hexdump(self.keyset[KEY_AUTH], short=True)
|
||||
print "MAC: ", utils.hexdump(self.keyset[KEY_MAC], short=True)
|
||||
print "KEK: ", utils.hexdump(self.keyset[KEY_KEK], short=True)
|
||||
|
||||
def cmd_resetkeyset(self, *args):
|
||||
def cmd_resetkeyset(self):
|
||||
"""Reset the keyset to the default keyset for this card."""
|
||||
self.keyset = dict(DEFAULT_KEYSET)
|
||||
|
||||
def cmd_savekeyset(self, *args):
|
||||
if len(args) != 1:
|
||||
raise TypeError, "Must give exactly one argument: the name of the file to save the keyset in."
|
||||
fd = file(args[0], "w")
|
||||
def cmd_savekeyset(self, filename):
|
||||
"""Saves the keyset to the named file."""
|
||||
fd = file(filename, "w")
|
||||
fd.write(self.keyset[KEY_AUTH])
|
||||
fd.write(self.keyset[KEY_MAC])
|
||||
fd.write(self.keyset[KEY_KEK])
|
||||
fd.close()
|
||||
|
||||
def cmd_loadkeyset(self, *args):
|
||||
if len(args) != 1:
|
||||
raise TypeError, "Must give exactly one argument: the name of the file to load the keyset from."
|
||||
fd = file(args[0], "r")
|
||||
def cmd_loadkeyset(self, filename):
|
||||
"""Loads the keyset from the named file."""
|
||||
fd = file(filename, "r")
|
||||
keys = fd.read(16*3)
|
||||
if len(keys) != 16*3:
|
||||
del keys
|
||||
|
@ -311,22 +308,14 @@ class Cyberflex_Card(Java_Card):
|
|||
|
||||
COMMANDS = dict(Java_Card.COMMANDS)
|
||||
COMMANDS.update( {
|
||||
"status": (cmd_status, "status [reference_control]",
|
||||
"""Execute a GetStatus command and return the result."""),
|
||||
"open_secure_channel": (cmd_secure, "open_secure_channel [keyset_version key_index security_level]",
|
||||
"""Open a secure channel. If given, keyset_version and key_index must be integers while security_level can be one of 0, clear, 1, mac, 3, macenc, mac+enc."""),
|
||||
"set_key": (cmd_setkey, "set_key key_index key",
|
||||
"""Set a key in the current keyset. key_index should be one of 0, all, 1, enc, auth, 2, mac, 3, kek."""),
|
||||
"print_keyset": (cmd_printkeyset, "print_keyset",
|
||||
"""Print the current keyset."""),
|
||||
"reset_keyset": (cmd_resetkeyset, "reset_keyset",
|
||||
"""Reset the keyset to the default keyset for this card."""),
|
||||
"save_keyset": (cmd_savekeyset, "save_keyset filename",
|
||||
"""Saves the keyset to the named file."""),
|
||||
"load_keyset": (cmd_loadkeyset, "load_keyset filename",
|
||||
"""Loads the keyset from the named file."""),
|
||||
"delete": (cmd_delete, "delete aid",
|
||||
"""Delete the object identified by aid.""")
|
||||
"status": cmd_status,
|
||||
"open_secure_channel": cmd_secure,
|
||||
"set_key": cmd_setkey,
|
||||
"print_keyset": cmd_printkeyset,
|
||||
"reset_keyset": cmd_resetkeyset,
|
||||
"save_keyset": cmd_savekeyset,
|
||||
"load_keyset": cmd_loadkeyset,
|
||||
"delete": cmd_delete
|
||||
} )
|
||||
STATUS_WORDS = dict(Java_Card.STATUS_WORDS)
|
||||
STATUS_WORDS.update( {
|
||||
|
|
|
@ -41,21 +41,19 @@ class Card:
|
|||
result = self.send_apdu(apdu)
|
||||
return result == self.SW_OK
|
||||
|
||||
def cmd_verify(self, *args):
|
||||
if len(args) != 2:
|
||||
raise TypeError, "Must give exactly two arguments: pin number and pin"
|
||||
pin_number = int(args[0], 0)
|
||||
pin_value = binascii.a2b_hex("".join(args[1].split()))
|
||||
def cmd_verify(self, pin_number, pin_value):
|
||||
"""Verify a PIN."""
|
||||
pin_number = int(pin_number, 0)
|
||||
pin_value = binascii.a2b_hex("".join(pin_value.split()))
|
||||
self.verify_pin(pin_number, pin_value)
|
||||
|
||||
def cmd_reset(self, *args):
|
||||
def cmd_reset(self):
|
||||
"""Reset the card."""
|
||||
self.card.reconnect(init=pycsc.SCARD_RESET_CARD)
|
||||
|
||||
COMMANDS = {
|
||||
"reset": (cmd_reset, "reset",
|
||||
"""Reset the card."""),
|
||||
"verify": (cmd_verify, "verify pin_number pin_value",
|
||||
"""Verify a PIN.""")
|
||||
"reset": cmd_reset,
|
||||
"verify": cmd_verify
|
||||
}
|
||||
|
||||
def _check_apdu(apdu):
|
||||
|
|
|
@ -18,19 +18,19 @@ class Java_Card(Card):
|
|||
content = aid) )
|
||||
return result
|
||||
|
||||
def cmd_selectapplication(self, *args):
|
||||
if len(args) != 1:
|
||||
raise TypeError, "Must give exactly one argument: the application to select."
|
||||
if self.APPLICATIONS.has_key(args[0]):
|
||||
aid = self.APPLICATIONS[args[0]]
|
||||
def cmd_selectapplication(self, application):
|
||||
"""Select an application on the card.
|
||||
application can be given either as hexadezimal aid or by symbolic name (if known)."""
|
||||
|
||||
if self.APPLICATIONS.has_key(application):
|
||||
aid = self.APPLICATIONS[application]
|
||||
else:
|
||||
aid = binascii.a2b_hex("".join(args[0].split()))
|
||||
aid = binascii.a2b_hex("".join(application.split()))
|
||||
result = self.select_application(aid)
|
||||
if len(result) > 2:
|
||||
print utils.hexdump(result[:-2])
|
||||
|
||||
COMMANDS = dict(Card.COMMANDS)
|
||||
COMMANDS.update( {
|
||||
"select_application": (cmd_selectapplication, "select_application application",
|
||||
"""Select an application on the card. application can be given either as hexadezimal aid or by symbolic name (if known).""")
|
||||
"select_application": cmd_selectapplication
|
||||
} )
|
||||
|
|
|
@ -2,74 +2,15 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
|
||||
import pycsc, utils, cards, os, re, binascii, sys, exceptions, traceback
|
||||
from shell import Shell
|
||||
print_backtrace = True
|
||||
|
||||
try:
|
||||
import readline
|
||||
except ImportError:
|
||||
print "No readline available"
|
||||
|
||||
if sys.modules.has_key("readline"):
|
||||
histfile = os.path.join(os.environ["HOME"], ".cyberflex-shell.history")
|
||||
try:
|
||||
readline.read_history_file(histfile)
|
||||
except IOError:
|
||||
pass
|
||||
import atexit
|
||||
atexit.register(readline.write_history_file, histfile)
|
||||
del os, histfile
|
||||
|
||||
readline.parse_and_bind("tab: complete")
|
||||
|
||||
class Cyberflex_Shell_Completer:
|
||||
def __init__(self, *commands):
|
||||
self.commands = commands
|
||||
self.card = None
|
||||
def set_card(self, card):
|
||||
self.card = card
|
||||
def complete(self, text, state):
|
||||
found = -1
|
||||
def check(text, state, cmd, found):
|
||||
if text == cmd[:len(text)]:
|
||||
found = found+1
|
||||
if found == state:
|
||||
return (found, cmd)
|
||||
else:
|
||||
return (found, None)
|
||||
|
||||
if self.card is not None:
|
||||
for (cmd, cmdspec) in self.card.COMMANDS.items():
|
||||
(found, retval) = check(text, state, cmd, found)
|
||||
if retval is not None:
|
||||
return retval
|
||||
for cmdset in self.commands:
|
||||
for (cmd, cmdspec) in cmdset.items():
|
||||
(found, retval) = check(text, state, cmd, found)
|
||||
if retval is not None:
|
||||
return retval
|
||||
|
||||
return False
|
||||
|
||||
def cmd_exit(card, *args):
|
||||
sys.exit()
|
||||
def cmd_help(card, *args):
|
||||
print "Cyberflex-shell help"
|
||||
print "\n%s Card commands:" % card.DRIVER_NAME
|
||||
for (cmd, cmdspec) in card.COMMANDS.items():
|
||||
print "%s\n\t\t%s" % (cmdspec[1], cmdspec[2])
|
||||
print "\nShell commands:"
|
||||
for (cmd, cmdspec) in COMMANDS.items():
|
||||
print "%s\n\t\t%s" % (cmdspec[1], cmdspec[2])
|
||||
def cmd_atr(card, *args):
|
||||
"""Print the ATR of the currently inserted card."""
|
||||
print "ATR: %s" % utils.hexdump(card.card.status()['ATR'], short=True)
|
||||
|
||||
COMMANDS = {
|
||||
"exit": (cmd_exit, "exit",
|
||||
"""Exit the shell."""),
|
||||
"help": (cmd_help, "help",
|
||||
"""Print this help."""),
|
||||
"atr": (cmd_atr, "atr",
|
||||
"""Print the ATR of the currently inserted card.""")
|
||||
"atr": cmd_atr
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -98,68 +39,34 @@ if __name__ == "__main__":
|
|||
card_class = cards.find_class(newState[0]['Atr'])
|
||||
|
||||
card = card_class()
|
||||
shell = Shell("cyberflex-shell")
|
||||
shell.register_commands(card, COMMANDS)
|
||||
shell.register_commands(card)
|
||||
|
||||
if sys.modules.has_key("readline"):
|
||||
completer = Cyberflex_Shell_Completer(COMMANDS)
|
||||
completer.set_card(card)
|
||||
readline.set_completer(completer.complete)
|
||||
|
||||
|
||||
line = ""
|
||||
apduregex = re.compile(r'^\s*([0-9a-f]{2}\s*){4,}$', re.I)
|
||||
while True:
|
||||
try:
|
||||
line = raw_input("%s > " % card.get_prompt())
|
||||
except EOFError:
|
||||
print
|
||||
break
|
||||
|
||||
line = line.strip()
|
||||
if line == "":
|
||||
continue
|
||||
def _update_prompt():
|
||||
shell.set_prompt(card.get_prompt() + " ")
|
||||
shell.register_pre_hook(_update_prompt)
|
||||
|
||||
def _clear_sw():
|
||||
card.sw_changed = False
|
||||
shell.register_pre_hook(_clear_sw)
|
||||
|
||||
parts = line.split()
|
||||
cmd = parts[0]
|
||||
if card.COMMANDS.has_key(cmd.lower()):
|
||||
cmdspec = card.COMMANDS[cmd.lower()]
|
||||
try:
|
||||
cmdspec[0](card, *parts[1:])
|
||||
except Exception:
|
||||
exctype, value = sys.exc_info()[:2]
|
||||
if exctype == exceptions.SystemExit:
|
||||
raise exctype, value
|
||||
print "%s: %s" % (exctype, value)
|
||||
if print_backtrace:
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
apduregex = re.compile(r'^\s*([0-9a-f]{2}\s*){4,}$', re.I)
|
||||
def do_raw_apdu(*args):
|
||||
apdu_string = "".join(args)
|
||||
if not apduregex.match(apdu_string):
|
||||
raise NotImplementedError
|
||||
|
||||
elif COMMANDS.has_key(cmd.lower()):
|
||||
cmdspec = COMMANDS[cmd.lower()]
|
||||
try:
|
||||
cmdspec[0](card, *parts[1:])
|
||||
except Exception:
|
||||
exctype, value = sys.exc_info()[:2]
|
||||
if exctype == exceptions.SystemExit:
|
||||
raise exctype, value
|
||||
print "%s: %s" % (exctype, value)
|
||||
if print_backtrace:
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
|
||||
elif apduregex.match(line):
|
||||
## Might be an APDU
|
||||
apdu = binascii.a2b_hex("".join(line.split()))
|
||||
try:
|
||||
apdu_binary = binascii.a2b_hex("".join(apdu_string.split()))
|
||||
apdu = utils.APDU(apdu_binary)
|
||||
response = card.send_apdu(apdu)
|
||||
print utils.hexdump(response)
|
||||
except Exception:
|
||||
exctype, value = sys.exc_info()[:2]
|
||||
print "%s: %s" % (exctype, value)
|
||||
if print_backtrace:
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
|
||||
else:
|
||||
print "Unknown command"
|
||||
shell.fallback = do_raw_apdu
|
||||
|
||||
def _print_sw():
|
||||
if card.sw_changed:
|
||||
print card.decode_statusword()
|
||||
shell.register_post_hook(_print_sw)
|
||||
|
||||
shell.run()
|
||||
|
|
Loading…
Reference in New Issue