fix gnuk_put_binary
authorNIIBE Yutaka <gniibe@fsij.org>
Tue, 5 Jun 2012 02:18:41 +0000 (11:18 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Tue, 5 Jun 2012 02:18:41 +0000 (11:18 +0900)
ChangeLog
tool/gnuk_put_binary.py
tool/gnuk_put_binary_libusb.py

index e0a4d49..b0ee12c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2012-06-05  Niibe Yutaka  <gniibe@fsij.org>
 
+       Firmware update key handling.
+       * tool/gnuk_put_binary.py (GnukToken.cmd_get_response): Handle
+       larger data such as card holder certificate.
+       (GnukToken.cmd_write_binary): Bug fix for cert do write.
+       (GnukToken.cmd_read_binary): New.
+       (main): Support firmware update key.
+
        Take advantage of the Thumb-2 "rbit" instruction.
        * regnual/regnual.c (fetch): Reverse bits.
        * src/usb_ctrl.c (rbit): New.  Deleted reverse32.
index 3c2dae4..63a5e60 100755 (executable)
@@ -4,7 +4,7 @@
 gnuk_put_binary.py - a tool to put binary to Gnuk Token
 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>
 
 This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -44,11 +44,17 @@ class GnukToken(object):
         self.connection = cardservice.connection
 
     def cmd_get_response(self, expected_len):
-        apdu = [0x00, 0xc0, 0x00, 0x00, expected_len]
-        response, sw1, sw2 = self.connection.transmit(apdu)
-        if not (sw1 == 0x90 and sw2 == 0x00):
-            raise ValueError, ("%02x%02x" % (sw1, sw2))
-        return response
+        result = []
+        while True:
+            apdu = [0x00, 0xc0, 0x00, 0x00, expected_len]
+            response, sw1, sw2 = self.connection.transmit(apdu)
+            result += response
+            if sw1 == 0x90 and sw2 == 0x00:
+                return result
+            elif sw1 != 0x61: 
+                raise ValueError, ("%02x%02x" % (sw1, sw2))
+            else:
+                expected_len = sw2
 
     def cmd_verify(self, who, passwd):
         apdu = [0x00, 0x20, 0x00, 0x80+who, len(passwd)] + s2l(passwd)
@@ -56,6 +62,15 @@ class GnukToken(object):
         if not (sw1 == 0x90 and sw2 == 0x00):
             raise ValueError, ("%02x%02x" % (sw1, sw2))
 
+    def cmd_read_binary(self, fileid):
+        apdu = [0x00, 0xb0, 0x80+fileid, 0x00] 
+        response, sw1, sw2 = self.connection.transmit(apdu)
+        if sw1 == 0x61:
+            response = self.cmd_get_response(sw2)
+        elif not (sw1 == 0x90 and sw2 == 0x00):
+            raise ValueError, ("%02x%02x" % (sw1, sw2))
+        return response
+
     def cmd_write_binary(self, fileid, data, is_update):
         count = 0
         data_len = len(data)
@@ -66,7 +81,7 @@ class GnukToken(object):
         while count*256 < data_len:
             if count == 0:
                 d = data[:256]
-                if len(d) <= 255: 
+                if len(d) <= 255:
                     apdu = [0x00, ins, 0x80+fileid, 0x00, len(d)] + s2l(d)
                 else:
                     apdu0 = [0x10, ins, 0x80+fileid, 0x00, 255] + s2l(d[:255])
@@ -74,18 +89,18 @@ class GnukToken(object):
                     apdu = [0x00, ins, 0x80+fileid, 0x00, 1 ] + s2l(d[255:])
             else:
                 d = data[256*count:256*(count+1)]
-                if len(d) <= 255: 
+                if len(d) <= 255:
                     apdu = [0x00, ins, count, 0x00, len(d)] + s2l(d)
                 else:
                     apdu0 = [0x10, ins, count, 0x00, 255] + s2l(d[:255])
                     response, sw1, sw2 = self.connection.transmit(apdu0)
-                    apdu = [0x00, ins, 0x80+fileid, 0x00, 1] + s2l(d[255:])
+                    apdu = [0x00, ins, count, 0x00, 1] + s2l(d[255:])
             response, sw1, sw2 = self.connection.transmit(apdu)
             if not (sw1 == 0x90 and sw2 == 0x00):
                 if is_update:
-                    raise ValueError, ("%02x%02x" % (sw1, sw2))
+                    raise ValueError, ("update failure: %02x%02x" % (sw1, sw2))
                 else:
-                    raise ValueError, ("%02x%02x" % (sw1, sw2))
+                    raise ValueError, ("write failure: %02x%02x" % (sw1, sw2))
             count += 1
 
     def cmd_select_openpgp(self):
@@ -124,15 +139,17 @@ def main(fileid, is_update, data, passwd):
 
     gnuk.cmd_verify(BY_ADMIN, passwd)
     gnuk.cmd_write_binary(fileid, data, is_update)
+    gnuk.cmd_select_openpgp()
     if fileid == 0:
-        gnuk.cmd_select_openpgp()
         data_in_device = gnuk.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 = gnuk.cmd_read_binary(fileid)
+        compare(data, data_in_device)
     elif fileid == 5:
-        gnuk.cmd_select_openpgp()
         data_in_device = gnuk.cmd_get_data(0x7f, 0x21)
         compare(data, data_in_device)
 
@@ -167,6 +184,13 @@ if __name__ == '__main__':
             exit(1)
         print "Writing serial number"
         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:
         fileid = 5              # Card holder certificate
         filename = sys.argv[1]
index 6115ca7..4c056fc 100755 (executable)
@@ -180,24 +180,28 @@ class gnuk_token:
             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, is_update):
         count = 0
         data_len = len(data)
+        if is_update:
+            ins = 0xd6
+        else:
+            ins = 0xd0
         while count*256 < data_len:
             if count == 0:
                 if len(data) < 128:
-                    cmd_data0 = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:128])
+                    cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128])
                     cmd_data1 = None
                 else:
-                    cmd_data0 = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:128], 0x10)
-                    cmd_data1 = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[128:256])
+                    cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128], 0x10)
+                    cmd_data1 = iso7816_compose(ins, 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_data0 = iso7816_compose(ins, 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+128:256*(count+1)])
+                    cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128], 0x10)
+                    cmd_data1 = iso7816_compose(ins, count, 0x00, data[256*count+128:256*(count+1)])
             sw = self.icc_send_cmd(cmd_data0)
             if len(sw) != 2:
                 raise ValueError, "cmd_write_binary 0"
@@ -211,37 +215,6 @@ class gnuk_token:
                     raise ValueError, "cmd_write_binary 1"
             count += 1
 
-    def cmd_update_binary(self, fileid, data):
-        count = 0
-        data_len = len(data)
-        while count*256 < data_len:
-            if count == 0:
-                if len(data) < 128:
-                    cmd_data0 = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[:128])
-                    cmd_data1 = None
-                else:
-                    cmd_data0 = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[:128], 0x10)
-                    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+128:256*(count+1)])
-            sw = self.icc_send_cmd(cmd_data0)
-            if len(sw) != 2:
-                raise ValueError, "cmd_update_binary 0"
-            if not (sw[0] == 0x90 and sw[1] == 0x00):
-                raise ValueError, "cmd_update_binary 0"
-            if cmd_data1:
-                sw = self.icc_send_cmd(cmd_data1)
-                if len(sw) != 2:
-                    raise ValueError, "cmd_update_binary 1"
-                if not (sw[0] == 0x90 and sw[1] == 0x00):
-                    raise ValueError, "cmd_update_binary 1"
-            count += 1
-
     def cmd_select_openpgp(self):
         cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01")
         sw = self.icc_send_cmd(cmd_data)
@@ -298,10 +271,7 @@ def main(fileid, is_update, data, passwd):
     elif icc.icc_get_status() == 1:
         icc.icc_power_on()
     icc.cmd_verify(BY_ADMIN, passwd)
-    if is_update:
-        icc.cmd_update_binary(fileid, data)
-    else:
-        icc.cmd_write_binary(fileid, data)
+    icc.cmd_write_binary(fileid, data, is_update)
     icc.cmd_select_openpgp()
     if fileid == 0:
         data_in_device = icc.cmd_get_data(0x00, 0x4f)