Support PyUSB 1.0, too
[gnuk/gnuk.git] / tool / upgrade_by_passwd.py
1 #! /usr/bin/python
2
3 """
4 upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token
5                        which is just shipped from factory
6
7 Copyright (C) 2012, 2013 Free Software Initiative of Japan
8 Author: NIIBE Yutaka <gniibe@fsij.org>
9
10 This file is a part of Gnuk, a GnuPG USB Token implementation.
11
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.
16
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.
21
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/>.
24 """
25
26 from gnuk_token import *
27 import sys, binascii, time, os
28 import rsa
29
30 DEFAULT_PW3 = "12345678"
31 BY_ADMIN = 3
32
33 KEYNO_FOR_AUTH=2 
34
35 def main(keyno, passwd, data_regnual, data_upgrade):
36     l = len(data_regnual)
37     if (l & 0x03) != 0:
38         data_regnual = data_regnual.ljust(l + 4 - (l & 0x03), chr(0))
39     crc32code = crc32(data_regnual)
40     print "CRC32: %04x\n" % crc32code
41     data_regnual += pack('<I', crc32code)
42
43     rsa_key = rsa.read_key_from_file('rsa_example.key')
44     rsa_raw_pubkey = rsa.get_raw_pubkey(rsa_key)
45
46     gnuk = get_gnuk_device()
47     gnuk.cmd_verify(BY_ADMIN, passwd)
48     gnuk.cmd_write_binary(1+keyno, rsa_raw_pubkey, False)
49
50     gnuk.cmd_select_openpgp()
51     challenge = gnuk.cmd_get_challenge()
52     digestinfo = binascii.unhexlify(SHA256_OID_PREFIX) + challenge
53     signed = rsa.compute_signature(rsa_key, digestinfo)
54     signed_bytes = rsa.integer_to_bytes_256(signed)
55     gnuk.cmd_external_authenticate(keyno, signed_bytes)
56     gnuk.stop_gnuk()
57     mem_info = gnuk.mem_info()
58     print "%08x:%08x" % mem_info
59
60     print "Downloading flash upgrade program..."
61     gnuk.download(mem_info[0], data_regnual)
62     print "Run flash upgrade program..."
63     gnuk.execute(mem_info[0] + len(data_regnual) - 4)
64     #
65     time.sleep(3)
66     gnuk.reset_device()
67     del gnuk
68     gnuk = None
69     #
70     print "Wait 3 seconds..."
71     time.sleep(3)
72     # Then, send upgrade program...
73     reg = None
74     for dev in gnuk_devices_by_vidpid():
75         try:
76             reg = regnual(dev)
77             print "Device: ", dev.filename
78             break
79         except:
80             pass
81     mem_info = reg.mem_info()
82     print "%08x:%08x" % mem_info
83     print "Downloading the program"
84     reg.download(mem_info[0], data_upgrade)
85     reg.protect()
86     reg.finish()
87     reg.reset_device()
88     return 0
89
90 if __name__ == '__main__':
91     if os.getcwd() != os.path.dirname(os.path.abspath(__file__)):
92         print "Please change working directory to: %s" % os.path.dirname(os.path.abspath(__file__))
93         exit(1)
94
95     passwd = DEFAULT_PW3
96     keyno = 0
97     while len(sys.argv) > 3:
98         option = sys.argv[1]
99         sys.argv.pop(1)
100         if option == '-p':
101             from getpass import getpass
102             passwd = getpass("Admin password: ")
103         elif option == '-k':
104             keyno = int(sys.argv[1])
105             sys.argv.pop(1)
106     filename_regnual = sys.argv[1]
107     filename_upgrade = sys.argv[2]
108     f = open(filename_regnual)
109     data_regnual = f.read()
110     f.close()
111     print "%s: %d" % (filename_regnual, len(data_regnual))
112     f = open(filename_upgrade)
113     data_upgrade = f.read()
114     f.close()
115     print "%s: %d" % (filename_upgrade, len(data_upgrade))
116     # First 4096-byte in data_upgrade is SYS, so, skip it.
117     main(keyno, passwd, data_regnual, data_upgrade[4096:])