mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-18 21:28:02 +00:00
hostapd: add support for rxkh_file
Initial support for dynamic reload of RxKHs. In order to check if RxKHs need reloading. RxKHs defined in the rxkh_file first has to be parsed and formated, the same way as hostapd will read from the file and also output, with the command GET_RXKHS. Then each list of RxKHs can be hashed and compared. Ucode implementation of hostapds rkh_derive_key() function. Hostapd converts hex keys with 128-bits or more when less than 256-bits to 256-bits, and truncates those that are more than 256-bits. See: https://w1.fi/cgit/hostap/commit/hostapd/config_file.c?id=245fc96e5f4b1c566b7eaa19180c774307ebed79 Signed-off-by: Sybil127 <sybil127@outlook.com> Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
97c8a94ec5
commit
7306ae401c
@ -11,6 +11,7 @@ hostapd.data.file_fields = {
|
||||
vlan_file: true,
|
||||
wpa_psk_file: true,
|
||||
sae_password_file: true,
|
||||
rxkh_file: true,
|
||||
accept_mac_file: true,
|
||||
deny_mac_file: true,
|
||||
eap_user_file: true,
|
||||
@ -351,6 +352,64 @@ function bss_reload_psk(bss, config, old_config)
|
||||
hostapd.printf(`Reload WPA PSK file for bss ${config.ifname}: ${ret}`);
|
||||
}
|
||||
|
||||
function normalize_rxkhs(txt)
|
||||
{
|
||||
const pat = {
|
||||
sep: "\x20",
|
||||
mac: "([[:xdigit:]]{2}:?){5}[[:xdigit:]]{2}",
|
||||
r0kh_id: "[\x21-\x7e]{1,48}",
|
||||
r1kh_id: "([[:xdigit:]]{2}:?){5}[[:xdigit:]]{2}",
|
||||
key: "[[:xdigit:]]{32,}",
|
||||
r0kh: function() {
|
||||
return "r0kh=" + this.mac + this.sep + this.r0kh_id;
|
||||
},
|
||||
r1kh: function() {
|
||||
return "r1kh=" + this.mac + this.sep + this.r1kh_id;
|
||||
},
|
||||
rxkh: function() {
|
||||
return "(" + this.r0kh() + "|" + this.r1kh() + ")" + this.sep + this.key;
|
||||
},
|
||||
};
|
||||
|
||||
let rxkhs = filter(
|
||||
split(txt, "\n"), (line) => match(line, regexp("^" + pat.rxkh() + "$"))
|
||||
) ?? [];
|
||||
|
||||
rxkhs = map(rxkhs, function(k) {
|
||||
k = split(k, " ", 3);
|
||||
k[0] = lc(k[0]);
|
||||
if(match(k[0], /^r1kh/)) {
|
||||
k[1] = lc(k[1]);
|
||||
}
|
||||
if(!k[2] = hostapd.rkh_derive_key(k[2])) {
|
||||
return;
|
||||
}
|
||||
return join(" ", k);
|
||||
});
|
||||
|
||||
return join("\n", sort(filter(rxkhs, length)));
|
||||
}
|
||||
|
||||
function bss_reload_rxkhs(bss, config, old_config)
|
||||
{
|
||||
let bss_rxkhs = join("\n", sort(split(bss.ctrl("GET_RXKHS"), "\n")));
|
||||
let bss_rxkhs_hash = hostapd.sha1(bss_rxkhs);
|
||||
|
||||
if (is_equal(config.hash.rxkh_file, bss_rxkhs_hash)) {
|
||||
if (is_equal(old_config.hash.rxkh_file, config.hash.rxkh_file))
|
||||
return;
|
||||
}
|
||||
|
||||
old_config.hash.rxkh_file = config.hash.rxkh_file;
|
||||
if (!is_equal(old_config, config))
|
||||
return;
|
||||
|
||||
let ret = bss.ctrl("RELOAD_RXKHS");
|
||||
ret ??= "failed";
|
||||
|
||||
hostapd.printf(`Reload RxKH file for bss ${config.ifname}: ${ret}`);
|
||||
}
|
||||
|
||||
function remove_file_fields(config)
|
||||
{
|
||||
return filter(config, (line) => !hostapd.data.file_fields[split(line, "=")[0]]);
|
||||
@ -652,6 +711,7 @@ function iface_reload_config(name, phydev, config, old_config)
|
||||
}
|
||||
|
||||
bss_reload_psk(bss, config.bss[i], bss_list_cfg[i]);
|
||||
bss_reload_rxkhs(bss, config.bss[i], bss_list_cfg[i]);
|
||||
if (is_equal(config.bss[i], bss_list_cfg[i]))
|
||||
continue;
|
||||
|
||||
@ -780,8 +840,13 @@ function iface_load_config(phy, radio, filename)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hostapd.data.file_fields[val[0]])
|
||||
bss.hash[val[0]] = hostapd.sha1(readfile(val[1]));
|
||||
if (hostapd.data.file_fields[val[0]]) {
|
||||
if (val[0] == "rxkh_file") {
|
||||
bss.hash[val[0]] = hostapd.sha1(normalize_rxkhs(readfile(val[1])));
|
||||
} else {
|
||||
bss.hash[val[0]] = hostapd.sha1(readfile(val[1]));
|
||||
}
|
||||
}
|
||||
|
||||
push(bss.data, line);
|
||||
}
|
||||
|
@ -823,6 +823,7 @@ int hostapd_ucode_init(struct hapd_interfaces *ifaces)
|
||||
{ "printf", uc_wpa_printf },
|
||||
{ "getpid", uc_wpa_getpid },
|
||||
{ "sha1", uc_wpa_sha1 },
|
||||
{ "rkh_derive_key", uc_wpa_rkh_derive_key },
|
||||
{ "freq_info", uc_wpa_freq_info },
|
||||
{ "add_iface", uc_hostapd_add_iface },
|
||||
{ "remove_iface", uc_hostapd_remove_iface },
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "utils/eloop.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/genetlink.h>
|
||||
@ -236,6 +237,40 @@ uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs)
|
||||
return ucv_string_new_length(hash_hex, 2 * ARRAY_SIZE(hash));
|
||||
}
|
||||
|
||||
uc_value_t *uc_wpa_rkh_derive_key(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
u8 oldkey[16];
|
||||
char *oldkey_hex;
|
||||
u8 key[SHA256_MAC_LEN];
|
||||
size_t key_len = sizeof(key);
|
||||
char key_hex[2 * ARRAY_SIZE(key) + 1];
|
||||
uc_value_t *val = uc_fn_arg(0);
|
||||
int i;
|
||||
|
||||
if (ucv_type(val) != UC_STRING)
|
||||
return NULL;
|
||||
|
||||
oldkey_hex = ucv_string_get(val);
|
||||
|
||||
if (!hexstr2bin(oldkey_hex, key, key_len))
|
||||
return ucv_string_new_length(oldkey_hex, 2 * ARRAY_SIZE(key));
|
||||
|
||||
if (hexstr2bin(oldkey_hex, oldkey, sizeof(oldkey))) {
|
||||
wpa_printf(MSG_ERROR, "Invalid RxKH key: '%s'", oldkey_hex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hmac_sha256_kdf(oldkey, sizeof(oldkey), "FT OLDKEY", NULL, 0, key, key_len) < 0) {
|
||||
wpa_printf(MSG_ERROR, "Invalid RxKH key: '%s'", oldkey_hex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key); i++)
|
||||
sprintf(key_hex + 2 * i, "%02x", key[i]);
|
||||
|
||||
return ucv_string_new_length(key_hex, 2 * ARRAY_SIZE(key));
|
||||
}
|
||||
|
||||
uc_vm_t *wpa_ucode_create_vm(void)
|
||||
{
|
||||
static uc_parse_config_t config = {
|
||||
|
@ -25,6 +25,7 @@ uc_value_t *uc_wpa_udebug_set(uc_vm_t *vm, size_t nargs);
|
||||
uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs);
|
||||
uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs);
|
||||
uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs);
|
||||
uc_value_t *uc_wpa_rkh_derive_key(uc_vm_t *vm, size_t nargs);
|
||||
uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user