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.
This commit is contained in:
Wim de With
2023-11-09 21:08:26 +01:00
committed by GitHub
parent d0d3cf78f9
commit 17a4aa962f
5 changed files with 34 additions and 59 deletions

2
base

Submodule base updated: 90681b01b9...99578f7921

View File

@@ -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"))

View File

@@ -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

View File

@@ -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

View File

@@ -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