mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-21 13:29:25 +01:00
plugins: remove dependency on ELL plugins
There has been a desire to remove the ELL plugin dependency from IWD which is the only consumer of the plugin API. This removes the dependency and prepares the tree for converting the existing ofono plugin into a regular module. sim_hardcoded was removed completely. This was originall implemented before full ofono support purely to test the IWD side of EAP-SIM/AKA. Since the ofono plugin (module-to-be) is now fully implemented there really isn't a need for sim_hardcoded.
This commit is contained in:
parent
2f51b51152
commit
bbcfde8743
@ -185,7 +185,6 @@ if DAEMON
|
||||
libexec_PROGRAMS += src/iwd
|
||||
|
||||
src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
|
||||
src/plugin.h src/plugin.c \
|
||||
src/netdev.h src/netdev.c \
|
||||
src/wiphy.h src/wiphy.c \
|
||||
src/device.c \
|
||||
@ -235,14 +234,9 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
|
||||
src_iwd_LDADD = $(ell_ldadd) -ldl
|
||||
src_iwd_DEPENDENCIES = $(ell_dependencies)
|
||||
|
||||
if SIM_HARDCODED
|
||||
builtin_modules += sim_hardcoded
|
||||
builtin_sources += plugins/sim_hardcoded.c
|
||||
endif
|
||||
|
||||
if OFONO
|
||||
builtin_modules += ofono
|
||||
builtin_sources += plugins/ofono.c
|
||||
builtin_sources += src/ofono.c
|
||||
endif
|
||||
|
||||
if DBUS_POLICY
|
||||
|
@ -13,6 +13,5 @@ fi
|
||||
--enable-hwsim \
|
||||
--enable-tools \
|
||||
--enable-ofono \
|
||||
--enable-sim-hardcoded \
|
||||
--disable-dbus-policy \
|
||||
--disable-systemd-service $*
|
||||
|
@ -291,11 +291,6 @@ AC_ARG_ENABLE([ofono], AC_HELP_STRING([--enable-ofono],
|
||||
[enable_ofono=${enableval}])
|
||||
AM_CONDITIONAL(OFONO, test "${enable_ofono}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE([sim_hardcoded], AC_HELP_STRING([--enable-sim-hardcoded],
|
||||
[enable hard coded SIM keys]),
|
||||
[enable_sim_hardcoded=${enableval}])
|
||||
AM_CONDITIONAL(SIM_HARDCODED, test "${enable_sim_hardcoded}" = "yes")
|
||||
|
||||
AC_CONFIG_FILES(Makefile)
|
||||
|
||||
AC_OUTPUT
|
||||
|
@ -1,399 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Wireless daemon for Linux
|
||||
*
|
||||
* Copyright (C) 2017-2019 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <ell/ell.h>
|
||||
#include <ell/plugin.h>
|
||||
|
||||
#include "src/simauth.h"
|
||||
|
||||
struct hardcoded_sim {
|
||||
char *identity;
|
||||
uint8_t sim_supported;
|
||||
uint8_t kc[NUM_RANDS_MAX][EAP_SIM_KC_LEN];
|
||||
uint8_t sres[NUM_RANDS_MAX][EAP_SIM_SRES_LEN];
|
||||
uint8_t aka_supported;
|
||||
uint8_t ki[EAP_AKA_KI_LEN];
|
||||
uint8_t opc[EAP_AKA_OPC_LEN];
|
||||
uint8_t amf[EAP_AKA_AMF_LEN];
|
||||
uint8_t sqn[EAP_AKA_SQN_LEN];
|
||||
struct iwd_sim_auth *auth;
|
||||
};
|
||||
|
||||
static struct hardcoded_sim *sim;
|
||||
|
||||
/*
|
||||
* Helper to XOR an array
|
||||
* to - result of XOR array
|
||||
* a - array 1
|
||||
* b - array 2
|
||||
* len - size of array
|
||||
*/
|
||||
#define XOR(to, a, b, len) \
|
||||
for (i = 0; i < len; i++) { \
|
||||
to[i] = a[i] ^ b[i]; \
|
||||
}
|
||||
|
||||
static int get_milenage(const uint8_t *opc, const uint8_t *k,
|
||||
const uint8_t *rand, const uint8_t *sqn, const uint8_t *amf,
|
||||
const uint8_t *autn_in, uint8_t *autn, uint8_t *ck, uint8_t *ik,
|
||||
uint8_t *res, uint8_t *auts)
|
||||
{
|
||||
/* algorithm variables: TEMP, IN1, OUT1, OUT2, OUT5 (OUT3/4 == IK/CK) */
|
||||
uint8_t temp[16];
|
||||
uint8_t in1[16];
|
||||
uint8_t out1[16], out2[16], out5[16];
|
||||
/* other variables */
|
||||
struct l_cipher *aes;
|
||||
int i;
|
||||
uint8_t tmp1[16];
|
||||
uint8_t tmp2[16];
|
||||
uint8_t sqn_autn[6];
|
||||
|
||||
aes = l_cipher_new(L_CIPHER_AES, k, 16);
|
||||
|
||||
/* temp = TEMP = E[RAND ^ OPc]k */
|
||||
XOR(tmp1, rand, opc, 16);
|
||||
l_cipher_encrypt(aes, tmp1, temp, 16);
|
||||
|
||||
/* IN1[0-47] = SQN[0-47] */
|
||||
memcpy(in1, sqn, 6);
|
||||
/* IN1[48-63] = AMF[0-15] */
|
||||
memcpy(in1 + 6, amf, 2);
|
||||
/* IN1[64-111] = SQN[0-47] */
|
||||
memcpy(in1 + 8, sqn, 6);
|
||||
/* IN1[112-127] = AMF[0-15] */
|
||||
memcpy(in1 + 14, amf, 2);
|
||||
|
||||
/*
|
||||
* f1 and f1* output OUT1
|
||||
*/
|
||||
/*
|
||||
* tmp1 = rot(IN1 ^ OPc)r1
|
||||
* r1 = 64 bits = 8 bytes
|
||||
*/
|
||||
for (i = 0; i < 16; i++)
|
||||
tmp1[(i + 8) % 16] = in1[i] ^ opc[i];
|
||||
|
||||
/* tmp2 = TEMP ^ tmp1 */
|
||||
XOR(tmp2, temp, tmp1, 16);
|
||||
/* tmp2 = E[tmp2]k */
|
||||
l_cipher_encrypt(aes, tmp2, tmp1, 16);
|
||||
/* out1 = OUT1 = tmp1 ^ opc */
|
||||
XOR(out1, tmp1, opc, 16);
|
||||
|
||||
/*
|
||||
* f2 outputs OUT2 (RES | AK)
|
||||
*
|
||||
* r2 = 0 == no rotation
|
||||
*/
|
||||
/* tmp1 = rot(TEMP ^ OPc)r2 */
|
||||
XOR(tmp1, temp, opc, 16);
|
||||
/* tmp1 ^ c2. c2 at bit 127 == 1 */
|
||||
tmp1[15] ^= 1;
|
||||
l_cipher_encrypt(aes, tmp1, out2, 16);
|
||||
|
||||
/* get RES from OUT2 */
|
||||
XOR(out2, out2, opc, 16);
|
||||
memcpy(res, out2 + 8, 8);
|
||||
|
||||
/* check input autn (AUTN ^ AK = SQN)*/
|
||||
XOR(sqn_autn, autn_in, out2, 6);
|
||||
|
||||
/* if SQN was not correct, generate AUTS */
|
||||
if (memcmp(sqn_autn, sqn, 6)) {
|
||||
/*
|
||||
* f5* outputs AK' (OUT5)
|
||||
*/
|
||||
for (i = 0; i < 16; i++)
|
||||
tmp1[(i + 4) % 16] = temp[i] ^ opc[i];
|
||||
|
||||
/* tmp1 ^ c5. c5 at bit 124 == 1 */
|
||||
tmp1[15] ^= 1 << 3;
|
||||
l_cipher_encrypt(aes, tmp1, out5, 16);
|
||||
/* out5 ^ opc */
|
||||
XOR(out5, out5, opc, 16);
|
||||
|
||||
XOR(auts, sqn, out5, 6);
|
||||
|
||||
/* run f1 with zero'd AMF to finish AUTS */
|
||||
in1[6] = 0x00;
|
||||
in1[7] = 0x00;
|
||||
in1[14] = 0x00;
|
||||
in1[15] = 0x00;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
tmp1[(i + 8) % 16] = in1[i] ^ opc[i];
|
||||
|
||||
/* tmp2 = TEMP ^ tmp1 */
|
||||
XOR(tmp2, temp, tmp1, 16);
|
||||
/* tmp2 = E[tmp2]k */
|
||||
l_cipher_encrypt(aes, tmp2, tmp1, 16);
|
||||
/* out1 = OUT1 = tmp1 ^ opc */
|
||||
XOR(out1, tmp1, opc, 16);
|
||||
|
||||
memcpy(auts + 6, in1 + 8, 8);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* AUTN = (SQN ^ AK) | AMF | MAC_A */
|
||||
XOR(autn, sqn, out2, 6);
|
||||
memcpy(autn + 6, amf, 2);
|
||||
memcpy(autn + 8, out1, 8);
|
||||
|
||||
if (memcmp(autn, autn_in, 16))
|
||||
return -2;
|
||||
|
||||
/*
|
||||
* f3 outputs CK (OUT3)
|
||||
*
|
||||
* tmp1 = rot(TEMP ^ OPc)r3
|
||||
*
|
||||
* r3 = 32 bits = 4 bytes
|
||||
*/
|
||||
for (i = 0; i < 16; i++)
|
||||
tmp1[(i + 12) % 16] = temp[i] ^ opc[i];
|
||||
|
||||
/* tmp1 ^ c3. c3 at bit 126 == 1 */
|
||||
tmp1[15] ^= 1 << 1;
|
||||
l_cipher_encrypt(aes, tmp1, ck, 16);
|
||||
/* ck ^ opc */
|
||||
XOR(ck, ck, opc, 16);
|
||||
|
||||
/*
|
||||
* f4 outputs IK (OUT4)
|
||||
*
|
||||
* tmp1 = rot(TEMP ^ OPc)r4
|
||||
*
|
||||
* r4 = 64 bits = 8 bytes
|
||||
*/
|
||||
for (i = 0; i < 16; i++)
|
||||
tmp1[(i + 8) % 16] = temp[i] ^ opc[i];
|
||||
|
||||
/* tmp1 ^ c4. c4 at bit 125 == 1 */
|
||||
tmp1[15] ^= 1 << 2;
|
||||
l_cipher_encrypt(aes, tmp1, ik, 16);
|
||||
/* ik ^ opc */
|
||||
XOR(ik, ik, opc, 16);
|
||||
|
||||
l_cipher_free(aes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_milenage(struct iwd_sim_auth *auth, const uint8_t *rand,
|
||||
const uint8_t *autn, sim_auth_check_milenage_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
uint8_t res[8];
|
||||
uint8_t ck[16];
|
||||
uint8_t ik[16];
|
||||
uint8_t _autn[16];
|
||||
uint8_t auts[14];
|
||||
int ret;
|
||||
|
||||
if (!sim->aka_supported)
|
||||
return -ENOTSUP;
|
||||
|
||||
ret = get_milenage(sim->opc, sim->ki, rand, sim->sqn, sim->amf,
|
||||
autn, _autn, ck, ik, res, auts);
|
||||
|
||||
/* ret == 0, success; ret == -1, sync failure; ret == -2, failure */
|
||||
if (ret == 0)
|
||||
cb(res, ck, ik, NULL, data);
|
||||
else if (ret == -1)
|
||||
cb(NULL, NULL, NULL, auts, data);
|
||||
else
|
||||
cb(NULL, NULL, NULL, NULL, data);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int run_gsm(struct iwd_sim_auth *auth, const uint8_t *rands,
|
||||
int num_rands, sim_auth_run_gsm_cb_t cb, void *data)
|
||||
{
|
||||
if (!sim->sim_supported)
|
||||
return -ENOTSUP;
|
||||
|
||||
cb((const uint8_t *)sim->sres, (const uint8_t *)sim->kc, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct iwd_sim_auth_driver hardcoded_sim_driver = {
|
||||
.name = "Hardcoded SIM driver",
|
||||
.check_milenage = check_milenage,
|
||||
.run_gsm = run_gsm
|
||||
};
|
||||
|
||||
static int sim_hardcoded_init(void)
|
||||
{
|
||||
void *kc;
|
||||
void *sres;
|
||||
void *ki;
|
||||
void *opc;
|
||||
void *amf;
|
||||
void *sqn;
|
||||
const char *str;
|
||||
size_t len;
|
||||
struct l_settings *key_settings;
|
||||
const char *config_path = getenv("IWD_SIM_KEYS");
|
||||
|
||||
if (!config_path) {
|
||||
l_debug("IWD_SIM_KEYS not set in env");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
key_settings = l_settings_new();
|
||||
|
||||
if (!l_settings_load_from_file(key_settings, config_path)) {
|
||||
l_error("No %s file found", config_path);
|
||||
l_settings_free(key_settings);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
sim = l_new(struct hardcoded_sim, 1);
|
||||
|
||||
if (l_settings_has_group(key_settings, "SIM")) {
|
||||
str = l_settings_get_value(key_settings, "SIM", "Kc");
|
||||
if (!str) {
|
||||
l_debug("Kc value must be present for SIM");
|
||||
goto try_aka;
|
||||
}
|
||||
|
||||
kc = l_util_from_hexstring(str, &len);
|
||||
memcpy(sim->kc, kc, len);
|
||||
l_free(kc);
|
||||
|
||||
str = l_settings_get_value(key_settings, "SIM", "SRES");
|
||||
if (!str) {
|
||||
l_debug("SRES value must be present for SIM");
|
||||
goto try_aka;
|
||||
}
|
||||
|
||||
sres = l_util_from_hexstring(str, &len);
|
||||
memcpy(sim->sres, sres, NUM_RANDS_MAX * EAP_SIM_SRES_LEN);
|
||||
l_free(sres);
|
||||
|
||||
str = l_settings_get_value(key_settings, "SIM", "Identity");
|
||||
if (!str) {
|
||||
l_debug("Identity setting must be present for SIM");
|
||||
goto try_aka;
|
||||
}
|
||||
|
||||
sim->identity = l_strdup(str);
|
||||
|
||||
sim->sim_supported = 1;
|
||||
}
|
||||
|
||||
try_aka:
|
||||
if (l_settings_has_group(key_settings, "AKA")) {
|
||||
str = l_settings_get_value(key_settings, "AKA", "KI");
|
||||
if (!str) {
|
||||
l_debug("KI value must be present for AKA");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ki = l_util_from_hexstring(str, &len);
|
||||
memcpy(sim->ki, ki, EAP_AKA_KI_LEN);
|
||||
l_free(ki);
|
||||
|
||||
str = l_settings_get_value(key_settings, "AKA", "OPC");
|
||||
if (!str) {
|
||||
l_debug("OPC value must be preset for AKA");
|
||||
goto end;
|
||||
}
|
||||
|
||||
opc = l_util_from_hexstring(str, &len);
|
||||
memcpy(sim->opc, opc, EAP_AKA_OPC_LEN);
|
||||
l_free(opc);
|
||||
|
||||
str = l_settings_get_value(key_settings, "AKA", "AMF");
|
||||
if (!str) {
|
||||
l_debug("AMF value must be present for AKA");
|
||||
goto end;
|
||||
}
|
||||
|
||||
amf = l_util_from_hexstring(str, &len);
|
||||
memcpy(sim->amf, amf, EAP_AKA_AMF_LEN);
|
||||
l_free(amf);
|
||||
|
||||
str = l_settings_get_value(key_settings, "AKA", "SQN");
|
||||
if (!str) {
|
||||
l_debug("SQN value must be present for AKA");
|
||||
goto end;
|
||||
}
|
||||
|
||||
sqn = l_util_from_hexstring(str, &len);
|
||||
memcpy(sim->sqn, sqn, EAP_AKA_SQN_LEN);
|
||||
l_free(sqn);
|
||||
|
||||
str = l_settings_get_value(key_settings, "AKA", "Identity");
|
||||
if (!str) {
|
||||
l_debug("Identity setting must be present for AKA");
|
||||
goto end;
|
||||
}
|
||||
|
||||
sim->identity = l_strdup(str);
|
||||
|
||||
sim->aka_supported = 1;
|
||||
}
|
||||
end:
|
||||
l_settings_free(key_settings);
|
||||
|
||||
if (!sim->sim_supported && !sim->aka_supported) {
|
||||
l_debug("error parsing config file, values missing");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sim->auth = iwd_sim_auth_create(&hardcoded_sim_driver);
|
||||
|
||||
iwd_sim_auth_set_nai(sim->auth, sim->identity);
|
||||
iwd_sim_auth_set_capabilities(sim->auth, sim->sim_supported,
|
||||
sim->aka_supported);
|
||||
|
||||
iwd_sim_auth_register(sim->auth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sim_hardcoded_exit(void)
|
||||
{
|
||||
iwd_sim_auth_remove(sim->auth);
|
||||
|
||||
if (sim)
|
||||
l_free(sim->identity);
|
||||
|
||||
l_free(sim);
|
||||
}
|
||||
|
||||
L_PLUGIN_DEFINE(__iwd_builtin_sim_hardcoded, sim_hardcoded,
|
||||
"Hardcoded SIM driver", "1.0", L_PLUGIN_PRIORITY_DEFAULT,
|
||||
sim_hardcoded_init, sim_hardcoded_exit)
|
16
src/main.c
16
src/main.c
@ -40,7 +40,6 @@
|
||||
#include "src/eap.h"
|
||||
#include "src/eapol.h"
|
||||
#include "src/rfkill.h"
|
||||
#include "src/plugin.h"
|
||||
#include "src/storage.h"
|
||||
#include "src/anqp.h"
|
||||
|
||||
@ -54,8 +53,6 @@ static const char *interfaces;
|
||||
static const char *nointerfaces;
|
||||
static const char *phys;
|
||||
static const char *nophys;
|
||||
static const char *plugins;
|
||||
static const char *noplugins;
|
||||
static const char *debugopt;
|
||||
static bool terminating;
|
||||
static bool nl80211_complete;
|
||||
@ -140,8 +137,6 @@ static void usage(void)
|
||||
"\t-I, --nointerfaces Interfaces to ignore\n"
|
||||
"\t-p, --phys Phys to manage\n"
|
||||
"\t-P, --nophys Phys to ignore\n"
|
||||
"\t-l, --plugin Plugins to include\n"
|
||||
"\t-L, --noplugin Plugins to exclude\n"
|
||||
"\t-d, --debug Enable debug output\n"
|
||||
"\t-v, --version Show version\n"
|
||||
"\t-h, --help Show help options\n");
|
||||
@ -154,8 +149,6 @@ static const struct option main_options[] = {
|
||||
{ "nointerfaces", required_argument, NULL, 'I' },
|
||||
{ "phys", required_argument, NULL, 'p' },
|
||||
{ "nophys", required_argument, NULL, 'P' },
|
||||
{ "plugin", required_argument, NULL, 'l' },
|
||||
{ "noplugin", required_argument, NULL, 'L' },
|
||||
{ "debug", optional_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ }
|
||||
@ -179,8 +172,6 @@ static void nl80211_appeared(const struct l_genl_family_info *info,
|
||||
l_main_quit();
|
||||
return;
|
||||
}
|
||||
|
||||
plugin_init(plugins, noplugins);
|
||||
}
|
||||
|
||||
static void request_name_callback(struct l_dbus *dbus, bool success,
|
||||
@ -393,12 +384,6 @@ int main(int argc, char *argv[])
|
||||
case 'P':
|
||||
nophys = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
plugins = optarg;
|
||||
break;
|
||||
case 'L':
|
||||
noplugins = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
if (optarg)
|
||||
debugopt = optarg;
|
||||
@ -504,7 +489,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
exit_status = l_main_run_with_signal(signal_handler, NULL);
|
||||
|
||||
plugin_exit();
|
||||
iwd_modules_exit();
|
||||
dbus_exit();
|
||||
l_dbus_destroy(dbus);
|
||||
|
Loading…
Reference in New Issue
Block a user