TCOS_Security_Environment: Handle 0x98/0x99 SM object

Passport_Application: Implement secure messaging


git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@176 f711b948-2313-0410-aaa9-d29f33439f0b
This commit is contained in:
hploetz 2007-02-12 20:09:48 +00:00
parent 617a1693b6
commit f01836762b
2 changed files with 99 additions and 9 deletions

View File

@ -1,7 +1,70 @@
from generic_application import Application
import struct, sha, binascii
from utils import hexdump, C_APDU
import crypto_utils
from tcos_card import SE_Config, TCOS_Security_Environment
import crypto_utils, tcos_card
class Passport_Security_Environment(TCOS_Security_Environment):
def __init__(self, card):
TCOS_Security_Environment.__init__(self, card)
self.last_vanilla_c_apdu = None
# Set up a fake SE config to be able to reuse the TCOS code
self.set_key( 1, self.card.KSenc)
enc_config = "\x80\x01\x0d\x83\x01\x01\x85\x00"
self.set_key( 2, self.card.KSmac)
mac_config = "\x80\x01\x0d\x83\x01\x02\x85\x00"
self.set_config( tcos_card.SE_APDU, tcos_card.TEMPLATE_CCT, SE_Config(mac_config) )
self.set_config( tcos_card.SE_RAPDU, tcos_card.TEMPLATE_CCT, SE_Config(mac_config) )
self.set_config( tcos_card.SE_APDU, tcos_card.TEMPLATE_CT, SE_Config(enc_config) )
self.set_config( tcos_card.SE_RAPDU, tcos_card.TEMPLATE_CT, SE_Config(enc_config) )
def before_send(self, apdu):
self.last_vanilla_c_apdu = C_APDU(apdu)
if (apdu.cla & 0x80 != 0x80) and (apdu.CLA & 0x0C != 0x0C):
# Transform for SM
apdu.CLA = apdu.CLA | 0x0C
apdu_string = binascii.b2a_hex(apdu.render())
new_apdu = [apdu_string[:8]]
new_apdu.append("YY")
if apdu.case() in (3,4):
new_apdu.append("87[01")
new_apdu.append(binascii.b2a_hex(apdu.data))
new_apdu.append("]")
if apdu.case() in (2,4):
if apdu.Le == 0:
apdu.Le = 0xff # FIXME: Probably not the right way
new_apdu.append("97(%02x)" % apdu.Le)
new_apdu.append("8E()00")
new_apdu_string = "".join(new_apdu)
apdu = C_APDU.parse_fancy_apdu(new_apdu_string)
return TCOS_Security_Environment.before_send(self, apdu)
def after_send(self, result):
if (self.last_vanilla_c_apdu.cla & 0x80 != 0x80) and (self.last_vanilla_c_apdu.CLA & 0x0C != 0x0C):
# Inject fake response descriptor so that TCOS_Security_Environment.after_send sees the need to authenticate/decrypt
response_descriptor = "\x99\x00\x8e\x00"
if self.last_vanilla_c_apdu.case() in (2,4):
response_descriptor = "\x87\x00" + response_descriptor
response_descriptor = "\xba" + chr(len(response_descriptor)) + response_descriptor
self.last_c_apdu.data = self.last_c_apdu.data + response_descriptor
return TCOS_Security_Environment.after_send(self, result)
def _mac(self, data):
(ssc,) = struct.unpack(">Q", self.card.ssc)
ssc = ssc + 1
self.card.ssc = struct.pack(">Q", ssc)
return Passport_Application._mac(self.card.KSmac, data, self.card.ssc, dopad=False)
class Passport_Application(Application):
DRIVER_NAME = "Passport"
@ -17,6 +80,7 @@ class Passport_Application(Application):
self.ssc = None
self.KSenc = None
self.KSmac = None
self.se = None
def derive_key(Kseed, c):
"""Derive a key according to TR-PKI mrtds ICC read-only access v1.1 annex E.1.
@ -106,17 +170,35 @@ class Passport_Application(Application):
self.KSmac = self.derive_key(KSseed, 2)
self.ssc = rnd_icc[-4:] + rnd_ifd[-4:]
if False:
self.KSenc = binascii.a2b_hex("979EC13B1CBFE9DCD01AB0FED307EAE5")
self.KSmac = binascii.a2b_hex("F1CB1F1FB5ADF208806B89DC579DC1F8")
self.ssc = binascii.a2b_hex("887022120C06C226")
if verbose:
print "KSseed = %s" % hexdump(KSseed)
print "KSenc = %s" % hexdump(self.KSenc)
print "KSmac = %s" % hexdump(self.KSmac)
print "ssc = %s" % hexdump(self.ssc)
self.se = Passport_Security_Environment(self)
def _mac(key, data, ssc = None):
def before_send(self, apdu):
if self.se:
apdu = self.se.before_send(apdu)
return apdu
def after_send(self, result):
if self.se:
result = self.se.after_send(result)
return result
def _mac(key, data, ssc = None, dopad=True):
if ssc:
data = ssc + data
topad = 8 - len(data) % 8
data = data + "\x80" + ("\x00" * (topad-1))
if dopad:
topad = 8 - len(data) % 8
data = data + "\x80" + ("\x00" * (topad-1))
a = crypto_utils.cipher(True, "des-cbc", key[:8], data)
b = crypto_utils.cipher(False, "des-ecb", key[8:16], a[-8:])
c = crypto_utils.cipher(True, "des-ecb", key[:8], b)
@ -133,6 +215,10 @@ class Passport_Application(Application):
return r
_make_random = staticmethod(_make_random)
def get_prompt(self):
return "(%s)%s" % (self.DRIVER_NAME, self.se and "[SM]" or "")
COMMANDS = {
"perform_bac": cmd_perform_bac,
}

View File

@ -126,8 +126,8 @@ class TCOS_Security_Environment(object):
tlv_data = self.decrypt_response(tlv_data)
#data = TLV_utils.pack(tlv_data, recalculate_length = True)
data = self.deformat_response(tlv_data)
new_apdu = R_APDU(rapdu, data = data)
data, sw = self.deformat_response(tlv_data, rapdu.sw)
new_apdu = R_APDU(rapdu, data = data, sw = sw)
result = new_apdu
except ValueError:
@ -137,8 +137,8 @@ class TCOS_Security_Environment(object):
return result
def deformat_response(self, tlv_data):
WHITELIST = (0x84, 0x86)
def deformat_response(self, tlv_data, sw):
WHITELIST = (0x84, 0x86, 0x98)
result = []
is_ok = True
@ -154,6 +154,10 @@ class TCOS_Security_Environment(object):
if t in WHITELIST:
if t == 0x86:
result.append( value[1:] )
elif t == 0x98:
if sw != value:
print "Warning: SW from SM not equal SW from RAPDU"
sw = value
else:
result.append( value )
else:
@ -161,7 +165,7 @@ class TCOS_Security_Environment(object):
else:
result.append( TLV_utils.pack( tlv_data, recalculate_length = True) )
return "".join(result)
return "".join(result), sw
def encrypt_command(self, tlv_data):
config = self.get_config(SE_APDU, TEMPLATE_CT)