somewhat more elegant implementation, allows 00 or ff filler bytes to be present
git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@148 f711b948-2313-0410-aaa9-d29f33439f0b
This commit is contained in:
parent
58505948ea
commit
98034cf1f7
|
@ -89,10 +89,10 @@ class TCOS_Security_Environment(object):
|
|||
|
||||
def process_apdu(self, apdu):
|
||||
if apdu.cla & 0x0c in (0x0c, 0x08):
|
||||
tlv_data = TLV_utils.unpack(apdu.data, with_marks = apdu.marks)
|
||||
tlv_data = TLV_utils.unpack(apdu.data, with_marks = apdu.marks, include_filler=True)
|
||||
|
||||
tlv_data = self.encrypt_command(tlv_data)
|
||||
tlv_data = self.authenticate_apdu(apdu, tlv_data)
|
||||
tlv_data = self.authenticate_command(apdu, tlv_data)
|
||||
|
||||
data = TLV_utils.pack(tlv_data, recalculate_length = True)
|
||||
new_apdu = C_APDU(apdu, data = data)
|
||||
|
@ -103,7 +103,6 @@ class TCOS_Security_Environment(object):
|
|||
|
||||
def process_rapdu(self, rapdu):
|
||||
if self.last_c_apdu.cla & 0x0c in (0x0c, 0x08):
|
||||
tlv_data = TLV_utils.unpack(rapdu.data)
|
||||
tlv_c_data = TLV_utils.unpack(self.last_c_apdu.data)
|
||||
|
||||
must_authenticate = False
|
||||
|
@ -112,21 +111,16 @@ class TCOS_Security_Environment(object):
|
|||
for response_template in data[2]:
|
||||
if response_template[0] == 0x8E:
|
||||
must_authenticate = True
|
||||
if must_authenticate:
|
||||
for data in tlv_data:
|
||||
if data[0] == 0x8E:
|
||||
must_authenticate = False
|
||||
|
||||
tlv_data = self.authenticate_apdu(rapdu, tlv_data)
|
||||
|
||||
if must_authenticate:
|
||||
print "| CRYPTOGRAPHIC CHECKSUM VERIFICATION ERROR"
|
||||
print "| No cryptographic checksum was included in the response"
|
||||
|
||||
data = TLV_utils.pack(tlv_data, recalculate_length = True)
|
||||
new_apdu = R_APDU(rapdu, data = data)
|
||||
|
||||
return new_apdu
|
||||
tlv_data = TLV_utils.unpack(rapdu.data, include_filler=True)
|
||||
tlv_data = self.authenticate_response(tlv_data)
|
||||
data = TLV_utils.pack(tlv_data, recalculate_length = True)
|
||||
new_apdu = R_APDU(rapdu, data = data)
|
||||
|
||||
return new_apdu
|
||||
else:
|
||||
return rapdu
|
||||
else:
|
||||
return rapdu
|
||||
|
||||
|
@ -139,7 +133,7 @@ class TCOS_Security_Environment(object):
|
|||
result = []
|
||||
for data in tlv_data:
|
||||
tag, length, value, marks = data
|
||||
if self.MARK_ENCRYPT in marks:
|
||||
if self.MARK_ENCRYPT in marks and tag not in (0xff, 0x00):
|
||||
t = tag & ~(0x01)
|
||||
if t == 0x84:
|
||||
value_ = self.pad(value)
|
||||
|
@ -176,54 +170,40 @@ class TCOS_Security_Environment(object):
|
|||
result.append(data[:3])
|
||||
|
||||
return result
|
||||
|
||||
def authenticate_apdu(self, apdu, tlv_data):
|
||||
# FIXME: This method does not work correctly when there are 00 or ff fill bytes in the TLV stream
|
||||
is_command = isinstance(apdu, C_APDU)
|
||||
config = self.get_config(is_command and SE_APDU or SE_RAPDU, TEMPLATE_CCT)
|
||||
|
||||
if config.algorithm is None: ## FIXME: Find out the correct way to determine this
|
||||
return tlv_data
|
||||
|
||||
print_buffer = False
|
||||
for data in tlv_data:
|
||||
if data[0] == 0x8E:
|
||||
print_buffer = True
|
||||
if not is_command: print
|
||||
print "| Calculating cryptographic checksum:"
|
||||
|
||||
def calculate_cct(self, config, tlv_data, startblock = "", print_buffer=True):
|
||||
"""Calculate the Cryptographic Checksum for some TLV data.
|
||||
tlv_data MUST be of the format generated by the include_filler=True parameter to unpack."""
|
||||
if print_buffer:
|
||||
print "| Calculating cryptographic checksum:"
|
||||
|
||||
def do_block(buffer, block):
|
||||
block = self.pad(block, pi = PI_ISO)
|
||||
block_ = self.pad("".join(block), pi = PI_ISO)
|
||||
offset = sum( [len(b) for b in buffer] )
|
||||
buffer.append(block)
|
||||
buffer.append(block_)
|
||||
del block[:]
|
||||
if print_buffer:
|
||||
print "|| " + "\n|| ".join( utils.hexdump( block, offset = offset ).splitlines() )
|
||||
print "|| " + "\n|| ".join( utils.hexdump( block_, offset = offset ).splitlines() )
|
||||
|
||||
buffer = []
|
||||
if is_command and apdu.cla & 0x0c == 0x0c:
|
||||
block = apdu.render()[:4]
|
||||
do_block(buffer, block)
|
||||
if startblock != "":
|
||||
do_block(buffer, [startblock])
|
||||
|
||||
need_pad = False
|
||||
|
||||
block = ""
|
||||
block = []
|
||||
for data in tlv_data:
|
||||
tag, length, value = data[:3]
|
||||
if tag & 0x01 == 0x01 or tag not in range(0x80, 0xbf+1):
|
||||
if (tag & 0x01 == 0x01 or tag not in range(0x80, 0xbf+1)) and tag not in (0xff, 0x00):
|
||||
value_ = TLV_utils.pack( (data, ), recalculate_length=True )
|
||||
|
||||
block = block + value_
|
||||
need_pad = True
|
||||
block.append( value_ )
|
||||
elif tag in (0xff, 0x00):
|
||||
block.append( chr(tag) )
|
||||
else:
|
||||
if need_pad:
|
||||
if len(block) > 0:
|
||||
do_block(buffer, block)
|
||||
block = ""
|
||||
need_pad = False
|
||||
|
||||
if need_pad:
|
||||
if len(block) > 0:
|
||||
do_block(buffer, block)
|
||||
block = ""
|
||||
need_pad = False
|
||||
|
||||
cct = crypto_utils.cipher( True,
|
||||
self.get_cipherspec(config),
|
||||
|
@ -234,34 +214,62 @@ class TCOS_Security_Environment(object):
|
|||
if print_buffer:
|
||||
print "| Result (Tag 0x8e, length: 0x%02x):" % len(cct)
|
||||
print "|| " + "\n|| ".join( utils.hexdump( cct ).splitlines() )
|
||||
if is_command: print
|
||||
|
||||
return cct
|
||||
|
||||
def authenticate_command(self, apdu, tlv_data):
|
||||
config = self.get_config(SE_APDU, TEMPLATE_CCT)
|
||||
|
||||
if config.algorithm is None: ## FIXME: Find out the correct way to determine this
|
||||
return tlv_data
|
||||
|
||||
result = []
|
||||
if is_command:
|
||||
for data in tlv_data:
|
||||
if data[0] == 0x8E:
|
||||
data = list(data)
|
||||
data[1] = len(cct)
|
||||
data[2] = cct
|
||||
data = tuple(data)
|
||||
result.append( data )
|
||||
else:
|
||||
for data in tlv_data:
|
||||
if data[0] == 0x8E:
|
||||
value = data[2]
|
||||
if len(value) >= 4 and cct.startswith(value):
|
||||
print "| Cryptographic checksum verifies OK"
|
||||
else:
|
||||
print "| CRYPTOGRAPHIC CHECKSUM VERIFICATION ERROR"
|
||||
print "| Is:"
|
||||
print "|| " + "\n|| ".join( utils.hexdump( value ).splitlines() )
|
||||
print "| Should be:"
|
||||
print "|| " + "\n|| ".join( utils.hexdump( cct ).splitlines() )
|
||||
else:
|
||||
result.append( data )
|
||||
|
||||
for data in tlv_data:
|
||||
if data[0] == 0x8e and data[1] == 0:
|
||||
startblock = ""
|
||||
if apdu.cla & 0x0c == 0x0c:
|
||||
startblock = apdu.render()[:4]
|
||||
cct = self.calculate_cct(config, tlv_data, startblock)
|
||||
print
|
||||
|
||||
data = tuple( (0x8e, len(cct), cct) + data[3:] )
|
||||
result.append(data)
|
||||
|
||||
return result
|
||||
|
||||
def authenticate_response(self, tlv_data):
|
||||
config = self.get_config(SE_RAPDU, TEMPLATE_CCT)
|
||||
|
||||
if config.algorithm is None: ## FIXME: Find out the correct way to determine this
|
||||
return tlv_data
|
||||
|
||||
print
|
||||
cct_claimed = None
|
||||
result = []
|
||||
|
||||
for data in tlv_data:
|
||||
if data[0] == 0x8E:
|
||||
cct_claimed = data[2]
|
||||
else:
|
||||
result.append( data )
|
||||
|
||||
if cct_claimed is None:
|
||||
print "| CRYPTOGRAPHIC CHECKSUM VERIFICATION ERROR"
|
||||
print "| No cryptographic checksum was included in the response"
|
||||
return tlv_data
|
||||
else:
|
||||
cct = self.calculate_cct(config, tlv_data)
|
||||
|
||||
if len(cct_claimed) >= 4 and cct.startswith(cct_claimed):
|
||||
print "| Cryptographic checksum verifies OK"
|
||||
return result
|
||||
else:
|
||||
print "| CRYPTOGRAPHIC CHECKSUM VERIFICATION ERROR"
|
||||
print "| Is:"
|
||||
print "|| " + "\n|| ".join( utils.hexdump( cct_claimed ).splitlines() )
|
||||
print "| Should be:"
|
||||
print "|| " + "\n|| ".join( utils.hexdump( cct ).splitlines() )
|
||||
return tlv_data
|
||||
|
||||
def get_cipherspec(self, config):
|
||||
g = globals()
|
||||
|
|
Loading…
Reference in New Issue