Transitioning to new APDU code
git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@53 f711b948-2313-0410-aaa9-d29f33439f0b
This commit is contained in:
parent
f5e42ca71b
commit
c68e8bba2e
|
@ -16,10 +16,10 @@ SECURE_CHANNEL_MACENC = 3
|
||||||
MAC_LENGTH = 8
|
MAC_LENGTH = 8
|
||||||
|
|
||||||
class Cyberflex_Card(Java_Card):
|
class Cyberflex_Card(Java_Card):
|
||||||
APDU_INITIALIZE_UPDATE = APDU('\x80\x50\x00\x00')
|
APDU_INITIALIZE_UPDATE = C_APDU('\x80\x50\x00\x00')
|
||||||
APDU_EXTERNAL_AUTHENTICATE = APDU('\x84\x82\x00\x00')
|
APDU_EXTERNAL_AUTHENTICATE = C_APDU('\x84\x82\x00\x00')
|
||||||
APDU_GET_STATUS = APDU('\x84\xF2\x00\x00\x4f\x00')
|
APDU_GET_STATUS = C_APDU('\x84\xF2\x00\x00\x4f') ## TODO: C_APDU('\x84\xF2\x00\x00\x4f\x00') ?
|
||||||
APDU_DELETE = APDU('\x84\xe4\x00\x00')
|
APDU_DELETE = C_APDU('\x84\xe4\x00\x00')
|
||||||
DRIVER_NAME = "Cyberflex"
|
DRIVER_NAME = "Cyberflex"
|
||||||
|
|
||||||
ATRS = [
|
ATRS = [
|
||||||
|
@ -65,7 +65,7 @@ class Cyberflex_Card(Java_Card):
|
||||||
def before_send(self, apdu):
|
def before_send(self, apdu):
|
||||||
"""Will be called by send_apdu before sending a command APDU.
|
"""Will be called by send_apdu before sending a command APDU.
|
||||||
Is responsible for authenticating/encrypting commands when needed."""
|
Is responsible for authenticating/encrypting commands when needed."""
|
||||||
if apdu[0] == '\x84':
|
if apdu.cla == '\x84':
|
||||||
## Need security
|
## Need security
|
||||||
|
|
||||||
if self.secure_channel_state == SECURE_CHANNEL_NONE:
|
if self.secure_channel_state == SECURE_CHANNEL_NONE:
|
||||||
|
@ -73,16 +73,11 @@ class Cyberflex_Card(Java_Card):
|
||||||
if self.secure_channel_state == SECURE_CHANNEL_CLEAR:
|
if self.secure_channel_state == SECURE_CHANNEL_CLEAR:
|
||||||
return apdu
|
return apdu
|
||||||
elif self.secure_channel_state == SECURE_CHANNEL_MAC:
|
elif self.secure_channel_state == SECURE_CHANNEL_MAC:
|
||||||
if len(apdu) < 4:
|
apdu.lc = apdu.lc + MAC_LENGTH
|
||||||
raise Exception, "Malformed APDU"
|
|
||||||
elif len(apdu) == 4:
|
|
||||||
apdu = apdu + chr(MAC_LENGTH)
|
|
||||||
else:
|
|
||||||
apdu = apdu[:4] + chr( ord(apdu[4]) + MAC_LENGTH ) + apdu[5:]
|
|
||||||
|
|
||||||
mac = crypto_utils.calculate_MAC(self.session_key_mac, apdu, self.last_mac)
|
mac = crypto_utils.calculate_MAC(self.session_key_mac, apdu.render(), self.last_mac)
|
||||||
self.last_mac = mac
|
self.last_mac = mac
|
||||||
apdu = apdu + mac
|
apdu.data = apdu.data + mac
|
||||||
elif self.secure_channel_state == SECURE_CHANNEL_MACENC:
|
elif self.secure_channel_state == SECURE_CHANNEL_MACENC:
|
||||||
raise Exception, "MAC+Enc Not implemented yet"
|
raise Exception, "MAC+Enc Not implemented yet"
|
||||||
return apdu
|
return apdu
|
||||||
|
@ -112,9 +107,9 @@ class Cyberflex_Card(Java_Card):
|
||||||
|
|
||||||
host_challenge = crypto_utils.generate_host_challenge()
|
host_challenge = crypto_utils.generate_host_challenge()
|
||||||
|
|
||||||
apdu = APDU(self.APDU_INITIALIZE_UPDATE,
|
apdu = C_APDU(self.APDU_INITIALIZE_UPDATE,
|
||||||
p1 = keyset_version, p2 = key_index,
|
p1 = keyset_version, p2 = key_index,
|
||||||
content = host_challenge)
|
data = host_challenge)
|
||||||
|
|
||||||
self.secure_channel_state = SECURE_CHANNEL_NONE
|
self.secure_channel_state = SECURE_CHANNEL_NONE
|
||||||
self.last_mac = '\x00' * 8
|
self.last_mac = '\x00' * 8
|
||||||
|
@ -122,11 +117,11 @@ class Cyberflex_Card(Java_Card):
|
||||||
self.session_key_mac = None
|
self.session_key_mac = None
|
||||||
|
|
||||||
result = self.send_apdu(apdu)
|
result = self.send_apdu(apdu)
|
||||||
if result[-2:] != self.SW_OK:
|
if result.sw != self.SW_OK:
|
||||||
raise Exception, "Statusword after InitializeUpdate was %s. Warning: No successful ExternalAuthenticate; keyset might be locked soon" % binascii.b2a_hex(result[-2:])
|
raise Exception, "Statusword after InitializeUpdate was %s. Warning: No successful ExternalAuthenticate; keyset might be locked soon" % binascii.b2a_hex(result[-2:])
|
||||||
|
|
||||||
card_challenge = result[12:20]
|
card_challenge = result.data[12:20]
|
||||||
card_cryptogram = result[20:28]
|
card_cryptogram = result.data[20:28]
|
||||||
|
|
||||||
self.session_key_enc = crypto_utils.get_session_key(
|
self.session_key_enc = crypto_utils.get_session_key(
|
||||||
self.keyset[KEY_AUTH], host_challenge, card_challenge)
|
self.keyset[KEY_AUTH], host_challenge, card_challenge)
|
||||||
|
@ -140,15 +135,15 @@ class Cyberflex_Card(Java_Card):
|
||||||
host_cryptogram = crypto_utils.calculate_host_cryptogram(
|
host_cryptogram = crypto_utils.calculate_host_cryptogram(
|
||||||
self.session_key_enc, card_challenge, host_challenge)
|
self.session_key_enc, card_challenge, host_challenge)
|
||||||
|
|
||||||
apdu = APDU(self.APDU_EXTERNAL_AUTHENTICATE,
|
apdu = C_APDU(self.APDU_EXTERNAL_AUTHENTICATE,
|
||||||
p1 = security_level, p2 = 0,
|
p1 = security_level, p2 = 0,
|
||||||
content = host_cryptogram)
|
data = host_cryptogram)
|
||||||
|
|
||||||
self.secure_channel_state = SECURE_CHANNEL_MAC
|
self.secure_channel_state = SECURE_CHANNEL_MAC
|
||||||
result = self.send_apdu(apdu)
|
result = self.send_apdu(apdu)
|
||||||
self.secure_channel_state = security_level
|
self.secure_channel_state = security_level
|
||||||
|
|
||||||
if result[-2:] != self.SW_OK:
|
if result.sw != self.SW_OK:
|
||||||
self.secure_channel_state = SECURE_CHANNEL_NONE
|
self.secure_channel_state = SECURE_CHANNEL_NONE
|
||||||
raise Exception, "Statusword after ExternalAuthenticate was %s. Warning: No successful ExternalAuthenticate; keyset might be locked soon" % binascii.b2a_hex(result[-2:])
|
raise Exception, "Statusword after ExternalAuthenticate was %s. Warning: No successful ExternalAuthenticate; keyset might be locked soon" % binascii.b2a_hex(result[-2:])
|
||||||
|
|
||||||
|
@ -174,7 +169,7 @@ class Cyberflex_Card(Java_Card):
|
||||||
Returns: the response APDU which can be parsed with
|
Returns: the response APDU which can be parsed with
|
||||||
utils.parse_status()"""
|
utils.parse_status()"""
|
||||||
return self.send_apdu(
|
return self.send_apdu(
|
||||||
APDU(self.APDU_GET_STATUS,
|
C_APDU(self.APDU_GET_STATUS,
|
||||||
p1 = reference_control)
|
p1 = reference_control)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -183,11 +178,11 @@ class Cyberflex_Card(Java_Card):
|
||||||
print "Cowardly refusing to delete the card manager."
|
print "Cowardly refusing to delete the card manager."
|
||||||
raise ValueError, "Undeletable object"
|
raise ValueError, "Undeletable object"
|
||||||
tlvaid = chr(0x4f) + chr(len(aid)) + aid
|
tlvaid = chr(0x4f) + chr(len(aid)) + aid
|
||||||
apdu = APDU(self.APDU_DELETE,
|
apdu = C_APDU(self.APDU_DELETE,
|
||||||
content = tlvaid)
|
data = tlvaid)
|
||||||
result = self.send_apdu(apdu)
|
result = self.send_apdu(apdu)
|
||||||
|
|
||||||
return result[0] == 0x0
|
return result.data[0] == 0x0
|
||||||
|
|
||||||
def cmd_delete(self, aid):
|
def cmd_delete(self, aid):
|
||||||
"""Delete the object identified by aid."""
|
"""Delete the object identified by aid."""
|
||||||
|
@ -198,7 +193,7 @@ class Cyberflex_Card(Java_Card):
|
||||||
"""Execute a GetStatus command and return the result."""
|
"""Execute a GetStatus command and return the result."""
|
||||||
reference_control = int(reference_control, 0)
|
reference_control = int(reference_control, 0)
|
||||||
result = self.get_status(reference_control)
|
result = self.get_status(reference_control)
|
||||||
utils.parse_status(result[:-2])
|
utils.parse_status(result.data)
|
||||||
|
|
||||||
def cmd_secure(self, keyset_version=None, key_index=None, security_level=None):
|
def cmd_secure(self, keyset_version=None, key_index=None, security_level=None):
|
||||||
"""Open a secure channel.
|
"""Open a secure channel.
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import crypto_utils, utils, pycsc, binascii, fnmatch
|
import crypto_utils, utils, pycsc, binascii, fnmatch
|
||||||
from utils import APDU
|
from utils import C_APDU, R_APDU
|
||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
#DEBUG = False
|
#DEBUG = False
|
||||||
|
|
||||||
class Card:
|
class Card:
|
||||||
APDU_GET_RESPONSE = APDU("\x00\xC0\x00\x00")
|
APDU_GET_RESPONSE = C_APDU("\x00\xC0\x00\x00")
|
||||||
APDU_VERIFY_PIN = APDU("\x00\x20\x00\x00")
|
APDU_VERIFY_PIN = C_APDU("\x00\x20\x00\x00")
|
||||||
SW_OK = '\x90\x00'
|
SW_OK = '\x90\x00'
|
||||||
ATRS = []
|
ATRS = []
|
||||||
DRIVER_NAME = "Generic"
|
DRIVER_NAME = "Generic"
|
||||||
|
@ -40,10 +40,10 @@ class Card:
|
||||||
self.sw_changed = False
|
self.sw_changed = False
|
||||||
|
|
||||||
def verify_pin(self, pin_number, pin_value):
|
def verify_pin(self, pin_number, pin_value):
|
||||||
apdu = APDU(self.APDU_VERIFY_PIN, P2 = pin_number,
|
apdu = C_APDU(self.APDU_VERIFY_PIN, P2 = pin_number,
|
||||||
content = pin_value)
|
data = pin_value)
|
||||||
result = self.send_apdu(apdu)
|
result = self.send_apdu(apdu)
|
||||||
return result == self.SW_OK
|
return result.sw == self.SW_OK
|
||||||
|
|
||||||
def cmd_verify(self, pin_number, pin_value):
|
def cmd_verify(self, pin_number, pin_value):
|
||||||
"""Verify a PIN."""
|
"""Verify a PIN."""
|
||||||
|
@ -60,32 +60,24 @@ class Card:
|
||||||
"verify": cmd_verify
|
"verify": cmd_verify
|
||||||
}
|
}
|
||||||
|
|
||||||
def _check_apdu(apdu):
|
|
||||||
return True
|
|
||||||
if len(apdu) < 4 or ((len(apdu) > 5) and len(apdu) != (ord(apdu[4])+5)):
|
|
||||||
print "Cowardly refusing to send invalid APDU:\n ", utils.hexdump(apdu, indent=2)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
_check_apdu = staticmethod(_check_apdu)
|
|
||||||
|
|
||||||
def _real_send(self, apdu):
|
def _real_send(self, apdu):
|
||||||
if not Card._check_apdu(apdu):
|
apdu_binary = apdu.render()
|
||||||
raise Exception, "Invalid APDU"
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print ">> " + utils.hexdump(apdu, indent = 3)
|
print ">> " + utils.hexdump(apdu_binary, indent = 3)
|
||||||
result = self.card.transmit(apdu)
|
|
||||||
|
result_binary = self.card.transmit(apdu_binary)
|
||||||
|
result = R_APDU(result_binary)
|
||||||
|
|
||||||
self.last_apdu = apdu
|
self.last_apdu = apdu
|
||||||
self.last_sw = result[-2:]
|
self.last_sw = result.sw
|
||||||
self.sw_changed = True
|
self.sw_changed = True
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "<< " + utils.hexdump(result, indent = 3)
|
print "<< " + utils.hexdump(result_binary, indent = 3)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def send_apdu(self, apdu):
|
def send_apdu(self, apdu):
|
||||||
if isinstance(apdu, APDU):
|
|
||||||
apdu = apdu.get_string(protocol = self.get_protocol()) ## FIXME
|
|
||||||
if not Card._check_apdu(apdu):
|
|
||||||
raise Exception, "Invalid APDU"
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "%s\nBeginning transaction %i" % ('-'*80, self._i)
|
print "%s\nBeginning transaction %i" % ('-'*80, self._i)
|
||||||
|
|
||||||
|
@ -94,10 +86,10 @@ class Card:
|
||||||
|
|
||||||
result = self._real_send(apdu)
|
result = self._real_send(apdu)
|
||||||
|
|
||||||
if len(result) == 2 and result[0] == '\x61':
|
if result.sw1 == 0x61:
|
||||||
## Need to call GetResponse
|
## Need to call GetResponse
|
||||||
gr_apdu = APDU(self.APDU_GET_RESPONSE, le = result[1]).get_string(protocol=0)
|
gr_apdu = C_APDU(self.APDU_GET_RESPONSE, le = result[1]).render() # FIXME
|
||||||
result = self._real_send(gr_apdu)
|
result = R_APDU(self._real_send(gr_apdu))
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "Ending transaction %i\n%s\n" % (self._i, '-'*80)
|
print "Ending transaction %i\n%s\n" % (self._i, '-'*80)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import utils, binascii
|
import utils, binascii
|
||||||
from generic_card import *
|
from generic_card import *
|
||||||
from utils import APDU
|
from utils import C_APDU
|
||||||
|
|
||||||
class Java_Card(Card):
|
class Java_Card(Card):
|
||||||
APDU_SELECT_APPLICATION = APDU("\x00\xa4\x04\x00")
|
APDU_SELECT_APPLICATION = C_APDU("\x00\xa4\x04\x00")
|
||||||
DRIVER_NAME = "Generic Java"
|
DRIVER_NAME = "Generic Java"
|
||||||
APPLICATIONS = {
|
APPLICATIONS = {
|
||||||
"muscle": "\xa0\x00\x00\x00\x01\x01"
|
"muscle": "\xa0\x00\x00\x00\x01\x01"
|
||||||
|
@ -14,8 +14,8 @@ class Java_Card(Card):
|
||||||
|
|
||||||
def select_application(self, aid):
|
def select_application(self, aid):
|
||||||
result = self.send_apdu(
|
result = self.send_apdu(
|
||||||
APDU(self.APDU_SELECT_APPLICATION,
|
C_APDU(self.APDU_SELECT_APPLICATION,
|
||||||
content = aid) )
|
data = aid) )
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def cmd_selectapplication(self, application):
|
def cmd_selectapplication(self, application):
|
||||||
|
@ -27,8 +27,8 @@ class Java_Card(Card):
|
||||||
else:
|
else:
|
||||||
aid = binascii.a2b_hex("".join(application.split()))
|
aid = binascii.a2b_hex("".join(application.split()))
|
||||||
result = self.select_application(aid)
|
result = self.select_application(aid)
|
||||||
if len(result) > 2:
|
if len(result.data) > 0:
|
||||||
print utils.hexdump(result[:-2])
|
print utils.hexdump(result.data)
|
||||||
|
|
||||||
COMMANDS = dict(Card.COMMANDS)
|
COMMANDS = dict(Card.COMMANDS)
|
||||||
COMMANDS.update( {
|
COMMANDS.update( {
|
||||||
|
|
|
@ -90,11 +90,11 @@ if __name__ == "__main__":
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
apdu_binary = binascii.a2b_hex("".join(apdu_string.split()))
|
apdu_binary = binascii.a2b_hex("".join(apdu_string.split()))
|
||||||
apdu = utils.APDU(apdu_binary)
|
apdu = utils.C_APDU(apdu_binary)
|
||||||
response = card.send_apdu(apdu)
|
response = card.send_apdu(apdu)
|
||||||
|
|
||||||
if len(response) > 2: ## The SW is already printed by _print_sw as a post_hook
|
if len(response.data) > 0: ## The SW is already printed by _print_sw as a post_hook
|
||||||
print utils.hexdump(response[:-2])
|
print utils.hexdump(response.data)
|
||||||
|
|
||||||
shell.fallback = do_raw_apdu
|
shell.fallback = do_raw_apdu
|
||||||
|
|
||||||
|
|
13
utils.py
13
utils.py
|
@ -248,6 +248,19 @@ class C_APDU(APDU):
|
||||||
buffer.append(chr(self.Le))
|
buffer.append(chr(self.Le))
|
||||||
|
|
||||||
return "".join(buffer)
|
return "".join(buffer)
|
||||||
|
|
||||||
|
def case(self):
|
||||||
|
"Return 1, 2, 3 or 4, depending on which ISO case we represent."
|
||||||
|
if self.Lc == 0:
|
||||||
|
if not hasattr(self, "_Le"):
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 2
|
||||||
|
else:
|
||||||
|
if not hasattr(self, "_Le"):
|
||||||
|
return 3
|
||||||
|
else:
|
||||||
|
return 4
|
||||||
|
|
||||||
class R_APDU(APDU):
|
class R_APDU(APDU):
|
||||||
"Class for a response APDU"
|
"Class for a response APDU"
|
||||||
|
|
Loading…
Reference in New Issue