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:
henryk 2005-10-09 02:06:32 +00:00
parent c584dad0b0
commit 5e5b85b28e
4 changed files with 83 additions and 189 deletions

View File

@ -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( {

View File

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

View File

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

View File

@ -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)
def _update_prompt():
shell.set_prompt(card.get_prompt() + " ")
shell.register_pre_hook(_update_prompt)
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 _clear_sw():
card.sw_changed = False
shell.register_pre_hook(_clear_sw)
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
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])
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:
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"
apdu_binary = binascii.a2b_hex("".join(apdu_string.split()))
apdu = utils.APDU(apdu_binary)
response = card.send_apdu(apdu)
print utils.hexdump(response)
shell.fallback = do_raw_apdu
def _print_sw():
if card.sw_changed:
print card.decode_statusword()
shell.register_post_hook(_print_sw)
shell.run()