diff --git a/ChangeLog b/ChangeLog index f399954..e9b5b9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2012-06-01 Niibe Yutaka + Support firmware update with public key authentication. + * tool/gnuk_upgrade.py (gpg_sign): New. * tool/gnuk_put_binary_libusb.py (main): Support firmware update key registration. diff --git a/tool/gnuk_upgrade.py b/tool/gnuk_upgrade.py index 43034c8..9677a01 100755 --- a/tool/gnuk_upgrade.py +++ b/tool/gnuk_upgrade.py @@ -40,8 +40,7 @@ CCID_PROTOCOL_0 = 0x00 def icc_compose(msg_type, data_len, slot, seq, param, data): return pack('BBBB', cls, ins, p1, p2) @@ -49,8 +48,19 @@ def iso7816_compose(ins, p1, p2, data): return pack('>BBBBB', cls, ins, p1, p2, data_len) + data class regnual: - def __init__(self, device): - self.__devhandle = device.open() + def __init__(self, dev): + conf = dev.configurations[0] + intf_alt = conf.interfaces[0] + intf = intf_alt[0] + if intf.interfaceClass != 0xff: + raise ValueError, "Wrong interface class" + self.__devhandle = dev.open() + try: + self.__devhandle.setConfiguration(conf) + except: + pass + self.__devhandle.claimInterface(intf) + self.__devhandle.setAltInterface(intf) def mem_info(self): mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0, @@ -301,7 +311,13 @@ class gnuk_token: raise ValueError, ("%02x%02x" % (sw[0], sw[1])) def cmd_external_authenticate(self, signed): - cmd_data = iso7816_compose(0x82, 0x00, 0x00, signed) + cmd_data = iso7816_compose(0x82, 0x00, 0x00, signed[0:128], cls=0x10) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError, sw + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError, ("%02x%02x" % (sw[0], sw[1])) + cmd_data = iso7816_compose(0x82, 0x00, 0x00, signed[128:]) sw = self.icc_send_cmd(cmd_data) if len(sw) != 2: raise ValueError, sw @@ -324,7 +340,7 @@ def compare(data_original, data_in_device): raise ValueError, "verify failed at %08x" % i i += 1 -def get_ccid_device(): +def ccid_devices(): busses = usb.busses() for bus in busses: devices = bus.devices @@ -335,13 +351,12 @@ def get_ccid_device(): if alt.interfaceClass == CCID_CLASS and \ alt.interfaceSubClass == CCID_SUBCLASS and \ alt.interfaceProtocol == CCID_PROTOCOL_0: - return dev, config, alt - raise ValueError, "Device not found" + yield dev, config, alt USB_VENDOR_FSIJ=0x234b USB_PRODUCT_GNUK=0x0000 -def get_gnuk_device(): +def gnuk_devices(): busses = usb.busses() for bus in busses: devices = bus.devices @@ -350,8 +365,7 @@ def get_gnuk_device(): continue if dev.idProduct != USB_PRODUCT_GNUK: continue - return dev - raise ValueError, "Device not found" + yield dev def to_string(t): result = "" @@ -359,21 +373,49 @@ def to_string(t): result += chr(c) return result -def main(data_regnual, data_upgrade): +from subprocess import check_output + +def gpg_sign(keygrip, hash): + result = check_output(["gpg-connect-agent", + "SIGKEY %s" % keygrip, + "SETHASH --hash=sha1 %s" % hash, + "PKSIGN", "/bye"]) + signed = "" + while True: + i = result.find('%') + if i < 0: + signed += result + break + hex_str = result[i+1:i+3] + signed += result[0:i] + signed += chr(int(hex_str,16)) + result = result[i+3:] + + pos = signed.index("D (7:sig-val(3:rsa(1:s256:") + 26 + signed = signed[pos:-7] + if len(signed) != 256: + raise ValueError, binascii.hexlify(signed) + return signed + +def main(keygrip, data_regnual, data_upgrade): data_regnual += pack('