source: trunk/fon/fonrsa/fonrsa/fonverify.lua

Last change on this file was 2196, checked in by matthijs, 5 years ago

fonrsa: Check if a firmware image has an upgrade script.

Since a while, a firmware running in DEV mode supports upgrading from
unsigned tarballs. However, since an unsigned tarball is just an
ordinary tarball, the current DEV firmware accepts any arbitrary tarball
and happily starts the flashing process. When this tarball does not
contain an "upgrade" script, the flashing process will fail, but only
after killing all networking services and too late too report the
failure to the user.

This commit makes sure that an unsigned tarball is at least checked for
the presence of an (executable) upgrade script, which should catch this
problem in most of the cases.

File size: 4.2 KB
Line 
1module("luci.fon.pkg.verify", package.seeall)
2fonrsa = require "fonrsa"
3posix = require "posix"
4
5-- check signature file using fonrsa.so
6function foncheckrsa(key, signature, file)
7        if fonrsa.open(key) == false then
8                return nil, "error opening public key file"
9        end
10        ret = fonrsa.verify(file, signature)
11        fonrsa.close()
12        return ret, nil
13end
14
15function cleanpath(file_1, file_2, file_3)
16        if file_1 ~= nil then os.execute("rm " .. file_1) end
17        if file_2 ~= nil then os.execute("rm " .. file_2) end
18        if file_3 ~= nil then os.execute("rm " .. file_3) end
19end
20
21function extract_file(tgz_path)
22        directory = os.tmpname()
23        os.execute("rm " .. directory)
24        if os.execute("mkdir " .. directory) ~= 0 then
25                cleanpath(tgz_path, nil, nil)
26                return nil, "error creating directory to extract to" .. path
27        end
28        if os.execute("tar -xzf" .. tgz_path .. " -C " .. directory) ~= 0 then
29                return nil, "error extracting tgz"
30        end
31        cleanpath(tgz_path, nil, nil)
32        return directory, nil
33end
34
35function verify_and_extract_file(tgz_path, signature_path, key_used)
36        if key_used ~= nil then
37                veredict, str = foncheckrsa(key_used, signature_path, tgz_path)
38                if veredict == nil then
39                        cleanpath(signature_path, tgz_path, fonfile)
40                        return nil, str
41                end
42                if veredict == false then
43                        cleanpath(signature_path, tgz_path, fonfile)
44                        return nil, "Signature verification failed"
45                end
46        end
47        directory = os.tmpname()
48        os.execute("rm " .. directory)
49        if os.execute("mkdir " .. directory) ~= 0 then
50                cleanpath(signature_path, tgz_path, nil)
51                return nil, "error creating directory to extract to" .. path
52        end
53        if os.execute("tar -xzf" .. tgz_path .. " -C " .. directory) ~= 0 then
54                return nil, "error extracting tgz"
55        end
56        -- Check that the upgrade script exists and is executable
57        local mode=posix.stat(directory .. "/upgrade", "mode")
58        if mode == nil or mode:sub(3, 3) ~= "x" then
59                return nil, "no upgrade script found"
60        end
61
62        cleanpath(signature_path, tgz_path, nil)
63        return directory, nil
64end
65
66function verify_and_extract_tgz(tgzfile, key_directory)
67        signature_path =  os.tmpname ()
68        ret, key, flags = fonrsa.extract(tgzfile, signature_path)
69        if (ret == false) then
70                return nil, "error extracting signature from tgz"
71        end
72        key_used = key_directory .. "public_fon_rsa_key_" .. key .. ".pem"
73        return verify_and_extract_file(tgzfile, signature_path, key_used)
74end
75
76function extract_unsigned_tgz(tgzfile)
77        return verify_and_extract_file(tgzfile, nil, nil)
78end
79
80--
81-- fonidentify returns filetype, key_number, error_string
82--
83-- being filetype:
84--  nil in case of error (and error_string != nil)
85--  one of:
86--   reflash
87--   hotfix
88--   plugin
89--   unsigned
90-- and key_number one of
91--  0..65536
92--  or nil if filetype is unsigned
93--
94function fonidentify(tgzfile)
95        return fonrsa.flags(tgzfile);
96end
97
98-- Verifies the signature in the .fon/.tgz file, extracts
99-- the contents to a temporal directory, checks if
100-- the restrictions contained in the file are met,
101-- and executes the installation script if they are.
102function fonverify(tgzfile, key_directory, allow_unsigned)
103        filetype, key_number, error_string = fonidentify(tgzfile)
104        if filetype == nil then
105                return nil, error_string
106        else 
107                if filetype == "unsigned" and allow_unsigned == false then
108                        return nil, "unsigned tgz files not allowed"
109                end
110        end
111        if filetype == "unsigned" then
112                directory, str = extract_unsigned_tgz(tgzfile)
113        else
114                directory, str = verify_and_extract_tgz(tgzfile, key_directory)
115        end
116        if directory == nil then
117                return nil, str
118        end
119        return directory, nil
120end
121
122function fonupgrade(directory)
123        ret = os.execute("cd " .. directory .." && ./upgrade > /dev/null 2>&1")
124        os.execute("rm -R " .. directory)
125        return ret, nil
126end
127
128function dotest()
129        dir, str = fonverify("example_plugin.tgz", "./", false)
130        -- dir, str = fonverify("example.fon", "/home/pablo/fon/keys/")
131        if dir == nil then
132                print(str)
133                return 1
134        end
135        print("Extracted dir is " .. dir)
136        res, str = fonupgrade(dir)
137        if res == 0 then
138                print("OK")
139        else
140                print("something went wrong " .. res .. "")
141        end
142end
143
144function doanothertest()
145        filetype, key_number, error_string = fonidentify("example_plugin.tgz")
146        if (error_string ~= nil) then
147                print("Error " .. err)
148        else
149                if filetype == "unsigned" then
150                        print "unsigned"
151                else
152                        print(filetype, " ", key_number)
153                end
154        end
155end
156
157function doposixtest()
158        posix.chdir("/etc")
159end
160
Note: See TracBrowser for help on using the repository browser.