firmware update key registration

This commit is contained in:
NIIBE Yutaka 2012-06-01 13:20:47 +09:00
parent 75b480f2c2
commit 78d9a56277
2 changed files with 113 additions and 37 deletions

View File

@ -1,5 +1,8 @@
2012-06-01 Niibe Yutaka <gniibe@fsij.org> 2012-06-01 Niibe Yutaka <gniibe@fsij.org>
* tool/gnuk_put_binary_libusb.py (main): Support firmware update
key registration.
Update of reGNUal. Update of reGNUal.
* regnual/regnual.c (main): Follow the change of usb_lld_init. * regnual/regnual.c (main): Follow the change of usb_lld_init.
(regnual_config_desc): Include interface descriptor. (regnual_config_desc): Include interface descriptor.

View File

@ -4,7 +4,7 @@
gnuk_put_binary.py - a tool to put binary to Gnuk Token gnuk_put_binary.py - a tool to put binary to Gnuk Token
This tool is for importing certificate, updating random number, etc. This tool is for importing certificate, updating random number, etc.
Copyright (C) 2011 Free Software Initiative of Japan Copyright (C) 2011, 2012 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org> Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation. This file is a part of Gnuk, a GnuPG USB Token implementation.
@ -41,13 +41,12 @@ CCID_PROTOCOL_0 = 0x00
def icc_compose(msg_type, data_len, slot, seq, param, data): def icc_compose(msg_type, data_len, slot, seq, param, data):
return pack('<BiBBBH', msg_type, data_len, slot, seq, 0, param) + data return pack('<BiBBBH', msg_type, data_len, slot, seq, 0, param) + data
def iso7816_compose(ins, p1, p2, data): def iso7816_compose(ins, p1, p2, data, cls=0x00):
cls = 0x00
data_len = len(data) data_len = len(data)
if data_len == 0: if data_len == 0:
return pack('>BBBB', cls, ins, p1, p2) return pack('>BBBB', cls, ins, p1, p2)
else: else:
return pack('>BBBBBh', cls, ins, p1, p2, 0, data_len) + data return pack('>BBBBB', cls, ins, p1, p2, data_len) + data
# This class only supports Gnuk (for now) # This class only supports Gnuk (for now)
class gnuk_token: class gnuk_token:
@ -150,27 +149,57 @@ class gnuk_token:
else: else:
raise ValueError, "icc_send_cmd" raise ValueError, "icc_send_cmd"
def cmd_get_response(self, expected_len):
cmd_data = iso7816_compose(0xc0, 0x00, 0x00, '') + pack('>B', expected_len)
response = self.icc_send_cmd(cmd_data)
return response[:-2]
def cmd_verify(self, who, passwd): def cmd_verify(self, who, passwd):
cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd) cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd)
sw = self.icc_send_cmd(cmd_data) sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2: if len(sw) != 2:
raise ValueError, "cmd_verify" raise ValueError, sw
if not (sw[0] == 0x90 and sw[1] == 0x00): if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_verify" raise ValueError, sw
def cmd_read_binary(self, fileid):
cmd_data = iso7816_compose(0xb0, 0x80+fileid, 0x00, '')
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if sw[0] != 0x61:
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def cmd_write_binary(self, fileid, data): def cmd_write_binary(self, fileid, data):
count = 0 count = 0
data_len = len(data) data_len = len(data)
while count*256 < data_len: while count*256 < data_len:
if count == 0: if count == 0:
cmd_data = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:256]) if len(data) < 128:
cmd_data0 = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:128])
cmd_data1 = None
else: else:
cmd_data = iso7816_compose(0xd0, count, 0x00, data[256*count:256*(count+1)]) cmd_data0 = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:128], 0x10)
sw = self.icc_send_cmd(cmd_data) cmd_data1 = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[128:256])
else:
if len(data[256*count:256*count+128]) < 128:
cmd_data0 = iso7816_compose(0xd0, count, 0x00, data[256*count:256*count+128])
cmd_data1 = None
else:
cmd_data0 = iso7816_compose(0xd0, count, 0x00, data[256*count:256*count+128], 0x10)
cmd_data1 = iso7816_compose(0xd0, count, 0x00, data[256*count:256*(count+1)])
sw = self.icc_send_cmd(cmd_data0)
if len(sw) != 2: if len(sw) != 2:
raise ValueError, "cmd_write_binary" raise ValueError, "cmd_write_binary 0"
if not (sw[0] == 0x90 and sw[1] == 0x00): if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_write_binary" raise ValueError, "cmd_write_binary 0"
if cmd_data1:
sw = self.icc_send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError, "cmd_write_binary 1"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_write_binary 1"
count += 1 count += 1
def cmd_update_binary(self, fileid, data): def cmd_update_binary(self, fileid, data):
@ -178,31 +207,48 @@ class gnuk_token:
data_len = len(data) data_len = len(data)
while count*256 < data_len: while count*256 < data_len:
if count == 0: if count == 0:
cmd_data = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[:256]) if len(data) < 128:
cmd_data0 = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[:128])
cmd_data1 = None
else: else:
cmd_data = iso7816_compose(0xd6, count, 0x00, data[256*count:256*(count+1)]) cmd_data0 = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[:128], 0x10)
sw = self.icc_send_cmd(cmd_data) cmd_data1 = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[128:256])
else:
if len(data[256*count:256*count+128]) < 128:
cmd_data0 = iso7816_compose(0xd6, count, 0x00, data[256*count:256*count+128])
cmd_data1 = None
else:
cmd_data0 = iso7816_compose(0xd6, count, 0x00, data[256*count:256*count+128], 0x10)
cmd_data1 = iso7816_compose(0xd6, count, 0x00, data[256*count:256*(count+1)])
sw = self.icc_send_cmd(cmd_data0)
if len(sw) != 2: if len(sw) != 2:
raise ValueError, "cmd_update_binary" raise ValueError, "cmd_write_binary 0"
if not (sw[0] == 0x90 and sw[1] == 0x00): if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_update_binary" raise ValueError, "cmd_write_binary 0"
if cmd_data1:
sw = self.icc_send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError, "cmd_write_binary 1"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_write_binary 1"
count += 1 count += 1
def cmd_select_openpgp(self): def cmd_select_openpgp(self):
cmd_data = iso7816_compose(0xa4, 0x04, 0x00, "\xD2\x76\x00\x01\x24\x01") cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01")
sw = self.icc_send_cmd(cmd_data) sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2: if len(sw) != 2:
raise ValueError, "cmd_select_openpgp" raise ValueError, sw
if not (sw[0] == 0x90 and sw[1] == 0x00): if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_select_openpgp" raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
def cmd_get_data(self, tagh, tagl): def cmd_get_data(self, tagh, tagl):
cmd_data = iso7816_compose(0xca, tagh, tagl, "") cmd_data = iso7816_compose(0xca, tagh, tagl, "")
result = self.icc_send_cmd(cmd_data) sw = self.icc_send_cmd(cmd_data)
sw = result[-2:] if len(sw) != 2:
if not (sw[0] == 0x90 and sw[1] == 0x00): raise ValueError, sw
raise ValueError, "cmd_get_data" if sw[0] != 0x61:
return result[:-2] raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def compare(data_original, data_in_device): def compare(data_original, data_in_device):
i = 0 i = 0
@ -211,7 +257,7 @@ def compare(data_original, data_in_device):
raise ValueError, "verify failed at %08x" % i raise ValueError, "verify failed at %08x" % i
i += 1 i += 1
def get_device(): def gnuk_devices():
busses = usb.busses() busses = usb.busses()
for bus in busses: for bus in busses:
devices = bus.devices devices = bus.devices
@ -222,33 +268,53 @@ def get_device():
if alt.interfaceClass == CCID_CLASS and \ if alt.interfaceClass == CCID_CLASS and \
alt.interfaceSubClass == CCID_SUBCLASS and \ alt.interfaceSubClass == CCID_SUBCLASS and \
alt.interfaceProtocol == CCID_PROTOCOL_0: alt.interfaceProtocol == CCID_PROTOCOL_0:
return dev, config, alt yield dev, config, alt
raise ValueError, "Device not found"
def main(fileid, is_update, data): DEFAULT_PW3 = "12345678"
dev, config, intf = get_device() BY_ADMIN = 3
def main(fileid, is_update, data, passwd):
icc = None
for (dev, config, intf) in gnuk_devices():
try:
icc = gnuk_token(dev, config, intf)
print "Device: ", dev.filename print "Device: ", dev.filename
print "Configuration: ", config.value print "Configuration: ", config.value
print "Interface: ", intf.interfaceNumber print "Interface: ", intf.interfaceNumber
icc = gnuk_token(dev, config, intf) break
except:
pass
if icc.icc_get_status() == 2: if icc.icc_get_status() == 2:
raise ValueError, "No ICC present" raise ValueError, "No ICC present"
elif icc.icc_get_status() == 1: elif icc.icc_get_status() == 1:
icc.icc_power_on() icc.icc_power_on()
icc.cmd_verify(3, "12345678") icc.cmd_verify(BY_ADMIN, passwd)
if is_update: if is_update:
icc.cmd_update_binary(fileid, data) icc.cmd_update_binary(fileid, data)
else: else:
icc.cmd_write_binary(fileid, data) icc.cmd_write_binary(fileid, data)
icc.cmd_select_openpgp() icc.cmd_select_openpgp()
if fileid == 1: if fileid == 0:
data = data[:-2] data_in_device = icc.cmd_get_data(0x00, 0x4f)
for d in data_in_device:
print "%02x" % d,
print
compare(data, data_in_device[8:])
elif fileid >= 1 and fileid <= 4:
data_in_device = icc.cmd_read_binary(fileid)
compare(data, data_in_device)
else:
data_in_device = icc.cmd_get_data(0x7f, 0x21) data_in_device = icc.cmd_get_data(0x7f, 0x21)
compare(data, data_in_device) compare(data, data_in_device)
icc.icc_power_off() icc.icc_power_off()
return 0 return 0
if __name__ == '__main__': if __name__ == '__main__':
passwd = DEFAULT_PW3
if sys.argv[1] == '-p':
from getpass import getpass
passwd = getpass("Admin password: ")
sys.argv.pop(1)
if sys.argv[1] == '-u': if sys.argv[1] == '-u':
is_update = True is_update = True
sys.argv.pop(1) sys.argv.pop(1)
@ -270,6 +336,13 @@ if __name__ == '__main__':
exit(1) exit(1)
print "Writing serial number" print "Writing serial number"
data = binascii.unhexlify(serial_data_hex) data = binascii.unhexlify(serial_data_hex)
elif sys.argv[1] == '-k': # firmware update key
keyno = sys.argv[2]
fileid = 1 + int(keyno)
filename = sys.argv[3]
f = open(filename)
data = f.read()
f.close()
else: else:
fileid = 5 # Card holder certificate fileid = 5 # Card holder certificate
filename = sys.argv[1] filename = sys.argv[1]
@ -278,4 +351,4 @@ if __name__ == '__main__':
f.close() f.close()
print "%s: %d" % (filename, len(data)) print "%s: %d" % (filename, len(data))
print "Updating card holder certificate" print "Updating card holder certificate"
main(fileid, is_update, data) main(fileid, is_update, data, passwd)