Fix connection bug with non-ASCII SSIDs in wpa_supplicant (#11089)

* Bump base

includes:

koreader/koreader-base#1691
koreader/koreader-base#1692
koreader/koreader-base#1689
koreader/koreader-base#1690
koreader/koreader-base#1693

* Integrate decoding of SSIDs within wpa_supplicant

The UTF-8 decoding of SSIDs is specific to wpa_supplicant. In this
patch, we move all of this decoding logic to the wpa_supplicant module.
We expose the raw bytes of the SSID to the NetworkMgr code, and make
sure to always fix bad UTF-8 before we display the SSID to the user.

Within the wpa_supplicant module, we replace the call to the
wpa_passphrase binary to get the PSK with a direct function call to
OpenSSL. This allows us to calculate the PSK over any arbitrary bytes,
including UTF-8. In the same vein, we use the hex-encoded SSID to
communicate with wpa_supplicant when setting up the network to support
arbitrary bytes in the SSID.

Unfortunately, we also remove the tests, as there is no way to unit test
local functions.
reviewable/pr11093/r1
Wim de With 6 months ago committed by GitHub
parent d0d3cf78f9
commit 17a4aa962f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1 +1 @@
Subproject commit 90681b01b97b80fa64abfb895854789ab9c5f199
Subproject commit 99578f7921fa63e326f9efdeca0c43c3897785d0

@ -1067,7 +1067,7 @@ function NetworkMgr:reconnectOrShowNetworkMenu(complete_callback, interactive)
end
UIManager:show(InfoMessage:new{
tag = "NetworkMgr", -- for crazy KOSync purposes
text = T(_("Connected to network %1"), BD.wrap(self.decodeSSID(ssid))),
text = T(_("Connected to network %1"), BD.wrap(util.fixUtf8(ssid, "<EFBFBD>"))),
timeout = 3,
})
else
@ -1119,23 +1119,6 @@ function NetworkMgr:setWirelessBackend(name, options)
require("ui/network/"..name).init(self, options)
end
function NetworkMgr.decodeSSID(text)
local decode = function(b)
local c = string.char(tonumber(b, 16))
-- This is a hack that allows us to make sure that any decoded backslash
-- does not get replaced in the step that replaces double backslashes.
if c == "\\" then
return "\\\\"
else
return c
end
end
local decoded = text:gsub("%f[\\]\\x(%x%x)", decode)
decoded = decoded:gsub("\\\\", "\\")
return util.fixUtf8(decoded, "<EFBFBD>")
end
-- set network proxy if global variable G_defaults:readSetting("NETWORK_PROXY") is defined
if G_defaults:readSetting("NETWORK_PROXY") then
NetworkMgr:setHTTPProxy(G_defaults:readSetting("NETWORK_PROXY"))

@ -2,6 +2,8 @@
WPA client helper for Kobo.
]]
local crypto = require("ffi/crypto")
local bin_to_hex = require("ffi/sha2").bin_to_hex
local FFIUtil = require("ffi/util")
local InfoMessage = require("ui/widget/infomessage")
local WpaClient = require("lj-wpaclient/wpaclient")
@ -13,6 +15,23 @@ local CLIENT_INIT_ERR_MSG = _("Failed to initialize network control client: %1."
local WpaSupplicant = {}
local function decodeSSID(ssid)
local decode = function(b)
local c = string.char(tonumber(b, 16))
-- This is a hack that allows us to make sure that any decoded backslash
-- does not get replaced in the step that replaces double backslashes.
if c == "\\" then
return "\\\\"
else
return c
end
end
local decoded = ssid:gsub("%f[\\]\\x(%x%x)", decode)
decoded = decoded:gsub("\\\\", "\\")
return decoded
end
--- Gets network list.
function WpaSupplicant:getNetworkList()
local wcli, err = WpaClient.new(self.wpa_supplicant.ctrl_interface)
@ -31,6 +50,7 @@ function WpaSupplicant:getNetworkList()
local curr_network = self:getCurrentNetwork()
for _, network in ipairs(list) do
network.ssid = decodeSSID(network.ssid)
network.signal_quality = network:getSignalQuality()
local saved_nw = saved_networks:readSetting(network.ssid)
if saved_nw then
@ -49,15 +69,7 @@ function WpaSupplicant:getNetworkList()
end
local function calculatePsk(ssid, pwd)
--- @todo calculate PSK with native function instead of shelling out
-- hostap's reference implementation is available at:
-- * /wpa_supplicant/wpa_passphrase.c
-- * /src/crypto/sha1-pbkdf2.c
-- see: <http://docs.ros.org/diamondback/api/wpa_supplicant/html/sha1-pbkdf2_8c_source.html>
local fp = io.popen(("wpa_passphrase %q %q"):format(ssid, pwd))
local out = fp:read("*a")
fp:close()
return string.match(out, "psk=([a-f0-9]+)")
return bin_to_hex(crypto.pbkdf2_hmac_sha1(pwd, ssid, 4096, 32))
end
--- Authenticates network.
@ -75,7 +87,7 @@ function WpaSupplicant:authenticateNetwork(network)
end
local nw_id = reply
reply, err = wcli:setNetwork(nw_id, "ssid", string.format("\"%s\"", network.ssid))
reply, err = wcli:setNetwork(nw_id, "ssid", bin_to_hex(network.ssid))
if reply == nil or reply == "FAIL" then
wcli:removeNetwork(nw_id)
return false, T("An error occurred while selecting network: %1.", err)
@ -185,6 +197,9 @@ function WpaSupplicant:getCurrentNetwork()
end
local nw = wcli:getCurrentNetwork()
wcli:close()
if nw ~= nil then
nw.ssid = decodeSSID(nw.ssid)
end
return nw
end

@ -56,6 +56,7 @@ local OverlapGroup = require("ui/widget/overlapgroup")
local Size = require("ui/size")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
local util = require("util")
local VerticalGroup = require("ui/widget/verticalgroup")
local Widget = require("ui/widget/widget")
local _ = require("gettext")
@ -106,7 +107,7 @@ local NetworkItem = InputContainer:extend{
icon_size = Screen:scaleBySize(32),
width = nil,
info = nil,
decoded_ssid = nil,
display_ssid = nil,
background = Blitbuffer.COLOR_WHITE,
}
@ -115,7 +116,7 @@ function NetworkItem:init()
if not self.info.ssid then
self.info.ssid = "[hidden]"
end
self.decoded_ssid = NetworkMgr.decodeSSID(self.info.ssid)
self.display_ssid = util.fixUtf8(self.info.ssid, "<EFBFBD>")
local wifi_icon
if string.find(self.info.flags, "WPA") then
@ -151,7 +152,7 @@ function NetworkItem:init()
},
horizontal_space,
TextWidget:new{
text = self.decoded_ssid,
text = self.display_ssid,
face = Font:getFace("cfont"),
},
},
@ -285,7 +286,7 @@ end
function NetworkItem:onEditNetwork()
local password_input
password_input = InputDialog:new{
title = self.decoded_ssid,
title = self.display_ssid,
input = self.info.password,
input_hint = _("password (leave empty for open networks)"),
input_type = "text",
@ -328,7 +329,7 @@ end
function NetworkItem:onAddNetwork()
local password_input
password_input = InputDialog:new{
title = self.decoded_ssid,
title = self.display_ssid,
input = "",
input_hint = _("password (leave empty for open networks)"),
input_type = "text",
@ -490,7 +491,7 @@ function NetworkSetting:init()
UIManager:close(self, "ui", self.dimen)
end
UIManager:show(InfoMessage:new{
text = T(_("Connected to network %1"), BD.wrap(connected_item.decoded_ssid)),
text = T(_("Connected to network %1"), BD.wrap(connected_item.display_ssid)),
timeout = 3,
})
if self.connect_callback then

@ -73,30 +73,6 @@ describe("network_manager module", function()
assert.is.same(release_ip_called, 0)
end)
describe("decodeSSID()", function()
local NetworkMgr = require("ui/network/manager")
it("should correctly unescape emoji", function()
assert.is_equal("📚", NetworkMgr.decodeSSID("\\xf0\\x9f\\x93\\x9a"))
end)
it("should correctly unescape multiple characters", function()
assert.is_equal("神舟五号", NetworkMgr.decodeSSID("\\xe7\\xa5\\x9e\\xe8\\x88\\x9f\\xe4\\xba\\x94\\xe5\\x8f\\xb7"))
end)
it("should ignore escaped backslashes", function()
assert.is_equal("\\x61", NetworkMgr.decodeSSID("\\\\x61"))
end)
it("should not remove encoded backslashes", function()
assert.is_equal("\\\\", NetworkMgr.decodeSSID("\\x5c\\"))
end)
it("should deal with invalid UTF-8 (relatively) gracefully", function()
assert.is_equal("<EFBFBD><EFBFBD>", NetworkMgr.decodeSSID("\\xe2\\x82"))
end)
end)
teardown(function()
function Device:initNetworkManager() end
function Device:hasWifiRestore() return false end

Loading…
Cancel
Save