4 gnuk_put_binary.py - a tool to put binary to Gnuk Token
5 This tool is for importing certificate, writing serial number, etc.
7 Copyright (C) 2011, 2012 Free Software Initiative of Japan
8 Author: NIIBE Yutaka <gniibe@fsij.org>
10 This file is a part of Gnuk, a GnuPG USB Token implementation.
12 Gnuk is free software: you can redistribute it and/or modify it
13 under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
17 Gnuk is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
20 License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import sys, os, binascii, string
30 # Assume only single CCID device is attached to computer and it's Gnuk Token
32 from smartcard.CardType import AnyCardType
33 from smartcard.CardRequest import CardRequest
34 from smartcard.util import toHexString
37 return [ ord(c) for c in s ]
39 class GnukToken(object):
41 cardtype = AnyCardType()
42 cardrequest = CardRequest(timeout=1, cardType=cardtype)
43 cardservice = cardrequest.waitforcard()
44 self.connection = cardservice.connection
46 def cmd_get_response(self, expected_len):
49 apdu = [0x00, 0xc0, 0x00, 0x00, expected_len]
50 response, sw1, sw2 = self.connection.transmit(apdu)
52 if sw1 == 0x90 and sw2 == 0x00:
55 raise ValueError, ("%02x%02x" % (sw1, sw2))
59 def cmd_verify(self, who, passwd):
60 apdu = [0x00, 0x20, 0x00, 0x80+who, len(passwd)] + s2l(passwd)
61 response, sw1, sw2 = self.connection.transmit(apdu)
62 if not (sw1 == 0x90 and sw2 == 0x00):
63 raise ValueError, ("%02x%02x" % (sw1, sw2))
65 def cmd_read_binary(self, fileid):
66 apdu = [0x00, 0xb0, 0x80+fileid, 0x00]
67 response, sw1, sw2 = self.connection.transmit(apdu)
69 response = self.cmd_get_response(sw2)
70 elif not (sw1 == 0x90 and sw2 == 0x00):
71 raise ValueError, ("%02x%02x" % (sw1, sw2))
74 def cmd_write_binary(self, fileid, data, is_update):
81 while count*256 < data_len:
85 apdu = [0x00, ins, 0x80+fileid, 0x00, len(d)] + s2l(d)
87 apdu0 = [0x10, ins, 0x80+fileid, 0x00, 255] + s2l(d[:255])
88 response, sw1, sw2 = self.connection.transmit(apdu0)
89 apdu = [0x00, ins, 0x80+fileid, 0x00, 1 ] + s2l(d[255:])
91 d = data[256*count:256*(count+1)]
93 apdu = [0x00, ins, count, 0x00, len(d)] + s2l(d)
95 apdu0 = [0x10, ins, count, 0x00, 255] + s2l(d[:255])
96 response, sw1, sw2 = self.connection.transmit(apdu0)
97 apdu = [0x00, ins, count, 0x00, 1] + s2l(d[255:])
98 response, sw1, sw2 = self.connection.transmit(apdu)
99 if not (sw1 == 0x90 and sw2 == 0x00):
101 raise ValueError, ("update failure: %02x%02x" % (sw1, sw2))
103 raise ValueError, ("write failure: %02x%02x" % (sw1, sw2))
106 def cmd_select_openpgp(self):
107 apdu = [0x00, 0xa4, 0x04, 0x0c, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01]
108 response, sw1, sw2 = self.connection.transmit(apdu)
110 response = self.cmd_get_response(sw2)
111 elif not (sw1 == 0x90 and sw2 == 0x00):
112 raise ValueError, ("%02x%02x" % (sw1, sw2))
114 def cmd_get_data(self, tagh, tagl):
115 apdu = [0x00, 0xca, tagh, tagl]
116 response, sw1, sw2 = self.connection.transmit(apdu)
118 response = self.cmd_get_response(sw2)
119 elif not (sw1 == 0x90 and sw2 == 0x00):
120 raise ValueError, ("%02x%02x" % (sw1, sw2))
123 def compare(data_original, data_in_device):
125 for d in data_original:
126 if ord(d) != data_in_device[i]:
127 raise ValueError, "verify failed at %08x" % i
130 DEFAULT_PW3 = "12345678"
133 def main(fileid, is_update, data, passwd):
136 gnuk.connection.connect()
137 print "Token:", gnuk.connection.getReader()
138 print "ATR:", toHexString( gnuk.connection.getATR() )
140 gnuk.cmd_verify(BY_ADMIN, passwd)
141 gnuk.cmd_write_binary(fileid, data, is_update)
142 gnuk.cmd_select_openpgp()
144 data_in_device = gnuk.cmd_get_data(0x00, 0x4f)
145 for d in data_in_device:
148 compare(data, data_in_device[8:])
149 elif fileid >= 1 and fileid <= 4:
150 data_in_device = gnuk.cmd_read_binary(fileid)
151 compare(data, data_in_device)
153 data_in_device = gnuk.cmd_get_data(0x7f, 0x21)
154 compare(data, data_in_device)
156 gnuk.connection.disconnect()
160 if __name__ == '__main__':
162 if sys.argv[1] == '-p':
163 from getpass import getpass
164 passwd = getpass("Admin password: ")
166 if sys.argv[1] == '-u':
171 if sys.argv[1] == '-s':
172 fileid = 0 # serial number
173 filename = sys.argv[2]
175 email = os.environ['EMAIL']
176 serial_data_hex = None
177 for line in f.readlines():
178 field = string.split(line)
179 if field[0] == email:
180 serial_data_hex = field[1].replace(':','')
182 if not serial_data_hex:
183 print "No serial number"
185 print "Writing serial number"
186 data = binascii.unhexlify(serial_data_hex)
187 elif sys.argv[1] == '-k': # firmware update key
189 fileid = 1 + int(keyno)
190 filename = sys.argv[3]
195 fileid = 5 # Card holder certificate
196 filename = sys.argv[1]
200 print "%s: %d" % (filename, len(data))
201 print "Updating card holder certificate"
202 main(fileid, is_update, data, passwd)