| 1 | module("luci.fon.pkg.verify", package.seeall) |
|---|
| 2 | fonrsa = require "fonrsa" |
|---|
| 3 | posix = require "posix" |
|---|
| 4 | |
|---|
| 5 | -- check signature file using fonrsa.so |
|---|
| 6 | function 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 |
|---|
| 13 | end |
|---|
| 14 | |
|---|
| 15 | function 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 |
|---|
| 19 | end |
|---|
| 20 | |
|---|
| 21 | function 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 |
|---|
| 33 | end |
|---|
| 34 | |
|---|
| 35 | function 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 |
|---|
| 64 | end |
|---|
| 65 | |
|---|
| 66 | function 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) |
|---|
| 74 | end |
|---|
| 75 | |
|---|
| 76 | function extract_unsigned_tgz(tgzfile) |
|---|
| 77 | return verify_and_extract_file(tgzfile, nil, nil) |
|---|
| 78 | end |
|---|
| 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 | -- |
|---|
| 94 | function fonidentify(tgzfile) |
|---|
| 95 | return fonrsa.flags(tgzfile); |
|---|
| 96 | end |
|---|
| 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. |
|---|
| 102 | function 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 |
|---|
| 120 | end |
|---|
| 121 | |
|---|
| 122 | function fonupgrade(directory) |
|---|
| 123 | ret = os.execute("cd " .. directory .." && ./upgrade > /dev/null 2>&1") |
|---|
| 124 | os.execute("rm -R " .. directory) |
|---|
| 125 | return ret, nil |
|---|
| 126 | end |
|---|
| 127 | |
|---|
| 128 | function 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 |
|---|
| 142 | end |
|---|
| 143 | |
|---|
| 144 | function 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 |
|---|
| 155 | end |
|---|
| 156 | |
|---|
| 157 | function doposixtest() |
|---|
| 158 | posix.chdir("/etc") |
|---|
| 159 | end |
|---|
| 160 | |
|---|