Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions autotests/testEncryptedProfiles/connection_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ def profile_is_encrypted(self, profile):

return True

def profile_has_psk_secret(self, profile):
with open('/tmp/iwd/' + profile) as f:
contents = f.read()

return any(secret in contents for secret in [
'Passphrase',
'PreSharedKey',
'SAE-PT-Group19',
'SAE-PT-Group20',
])

def validate(self, wd):
devices = wd.list_devices(1)
device = devices[0]
Expand Down Expand Up @@ -80,6 +91,22 @@ def test_agent_profile(self):

wd.unregister_psk_agent(psk_agent)

# Tests that an agent can request one-time use of a passphrase.
def test_agent_transient_profile(self):
wd = IWD(True)

psk_agent = PSKAgent("secret123", store=False)
wd.register_psk_agent(psk_agent)

with self.assertRaises(FileNotFoundError):
self.profile_has_psk_secret('ssidCCMP.psk')

self.validate(wd)

self.assertFalse(self.profile_has_psk_secret('ssidCCMP.psk'))

wd.unregister_psk_agent(psk_agent)

# Tests that an invalid profile gets re-written after an agent request
def test_invalid_profile_rewritten(self):
bad_config = '[Security]\nPassphrase=incorrect\n'
Expand Down
14 changes: 13 additions & 1 deletion autotests/util/iwd.py
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ def __str__(self):

class PSKAgent(dbus.service.Object):

def __init__(self, passphrases=[], users=[], namespace=ctx):
def __init__(self, passphrases=[], users=[], namespace=ctx, store=True):
global agent_count

if type(passphrases) != list:
Expand All @@ -1162,6 +1162,7 @@ def __init__(self, passphrases=[], users=[], namespace=ctx):
if type(users) != list:
users = [users]
self.users = users
self.store = store
self._path = '/test/agent/%s' % agent_count
self._bus = dbus.bus.BusConnection(address_or_type=namespace.dbus_address)

Expand Down Expand Up @@ -1193,6 +1194,17 @@ def RequestPassphrase(self, path):

return self.passphrases.pop(0)

@dbus.service.method(IWD_AGENT_INTERFACE, in_signature='o',
out_signature='sa{sv}')
def RequestPassphraseWithOptions(self, path):
print('Requested PSK with options for ' + path)

if not self.passphrases:
raise CanceledEx("canceled")

return (self.passphrases.pop(0),
{'Store': dbus.Boolean(self.store, variant_level=1)})

@dbus.service.method(IWD_AGENT_INTERFACE, in_signature='o',
out_signature='s')
def RequestPrivateKeyPassphrase(self, path):
Expand Down
12 changes: 12 additions & 0 deletions doc/agent-api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ Methods void Release() [noreply]

Possible Errors: net.connman.iwd.Agent.Error.Canceled

(string, dict) RequestPassphraseWithOptions(object network)

This method gets called when trying to connect to
a network and passphrase is required. Agents
implementing this method can return options for the
passphrase. If the Store boolean option is present
and false, IWD will use the passphrase for this
connection attempt but will not save it to the
network profile.

Possible Errors: net.connman.iwd.Agent.Error.Canceled

string RequestPrivateKeyPassphrase(object network)

This method gets called when connecting to
Expand Down
108 changes: 94 additions & 14 deletions src/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ enum agent_request_type {
struct agent_request {
enum agent_request_type type;
struct l_dbus_message *message;
char *path;
unsigned int id;
void *user_data;
void *user_callback;
struct l_dbus_message *trigger;
agent_request_destroy_func_t destroy;
bool passphrase_with_options;
};

struct agent {
Expand Down Expand Up @@ -126,6 +128,7 @@ static void agent_request_free(void *user_data)
if (request->destroy)
request->destroy(request->user_data);

l_free(request->path);
l_free(request);
}

Expand All @@ -134,19 +137,37 @@ static void passphrase_reply(struct l_dbus_message *reply,
{
const char *error, *text;
char *passphrase = NULL;
bool store = true;
enum agent_result result = AGENT_RESULT_FAILED;
agent_request_passphrase_func_t user_callback = request->user_callback;

if (l_dbus_message_get_error(reply, &error, &text))
goto done;

if (!l_dbus_message_get_arguments(reply, "s", &passphrase))
if (request->passphrase_with_options) {
struct l_dbus_message_iter options;
struct l_dbus_message_iter value;
const char *key;

if (!l_dbus_message_get_arguments(reply, "sa{sv}",
&passphrase, &options))
goto done;

while (l_dbus_message_iter_next_entry(&options, &key, &value)) {
if (!strcmp(key, "Store")) {
if (!l_dbus_message_iter_get_variant(&value,
"b", &store))
goto done;
}
}
} else if (!l_dbus_message_get_arguments(reply, "s", &passphrase))
goto done;

result = AGENT_RESULT_OK;

done:
user_callback(result, passphrase, request->trigger, request->user_data);
user_callback(result, passphrase, store, request->trigger,
request->user_data);
}

static void user_name_passwd_reply(struct l_dbus_message *reply,
Expand Down Expand Up @@ -224,6 +245,57 @@ static void agent_free(void *data)
}

static void agent_send_next_request(struct agent *agent);
static void agent_receive_reply(struct l_dbus_message *message,
void *user_data);

static struct l_dbus_message *agent_new_passphrase_message(struct agent *agent,
const char *path, bool with_options)
{
struct l_dbus_message *message;

message = l_dbus_message_new_method_call(dbus_get_bus(),
agent->owner,
agent->path,
IWD_AGENT_INTERFACE,
with_options ?
"RequestPassphraseWithOptions" :
"RequestPassphrase");

l_dbus_message_set_arguments(message, "o", path);

return message;
}

static bool agent_retry_passphrase_without_options(struct agent *agent,
struct agent_request *request,
struct l_dbus_message *reply)
{
const char *error, *text;

if (request->type != AGENT_REQUEST_TYPE_PASSPHRASE ||
!request->passphrase_with_options)
return false;

if (!l_dbus_message_get_error(reply, &error, &text))
return false;

if (strcmp(error, "org.freedesktop.DBus.Error.UnknownMethod") &&
strcmp(error, "org.freedesktop.DBus.Error.UnknownInterface"))
return false;

request->passphrase_with_options = false;
request->message = agent_new_passphrase_message(agent, request->path,
false);

agent->pending_id = l_dbus_send_with_reply(dbus_get_bus(),
request->message,
agent_receive_reply,
agent, NULL);

request->message = NULL;

return true;
}

static void request_timeout(struct l_timeout *timeout, void *user_data)
{
Expand All @@ -242,11 +314,17 @@ static void agent_receive_reply(struct l_dbus_message *message,
void *user_data)
{
struct agent *agent = user_data;
struct agent_request *pending;

l_debug("agent %p request id %u", agent, agent->pending_id);

agent->pending_id = 0;

pending = l_queue_peek_head(agent->requests);
if (pending && agent_retry_passphrase_without_options(agent, pending,
message))
return;

agent_finalize_pending(agent, message);

if (!agent->pending_id)
Expand Down Expand Up @@ -281,19 +359,23 @@ static unsigned int agent_queue_request(struct agent *agent,
int timeout, void *callback,
struct l_dbus_message *trigger,
void *user_data,
agent_request_destroy_func_t destroy)
agent_request_destroy_func_t destroy,
const char *path,
bool passphrase_with_options)
{
struct agent_request *request;

request = l_new(struct agent_request, 1);

request->type = type;
request->message = message;
request->path = l_strdup(path);
request->id = ++next_request_id;
request->user_data = user_data;
request->user_callback = callback;
request->trigger = l_dbus_message_ref(trigger);
request->destroy = destroy;
request->passphrase_with_options = passphrase_with_options;

agent->timeout_secs = timeout;

Expand Down Expand Up @@ -365,17 +447,12 @@ unsigned int agent_request_passphrase(const char *path,

l_debug("agent %p owner %s path %s", agent, agent->owner, agent->path);

message = l_dbus_message_new_method_call(dbus_get_bus(),
agent->owner,
agent->path,
IWD_AGENT_INTERFACE,
"RequestPassphrase");

l_dbus_message_set_arguments(message, "o", path);
message = agent_new_passphrase_message(agent, path, true);

return agent_queue_request(agent, AGENT_REQUEST_TYPE_PASSPHRASE,
message, agent_timeout_input_request(),
callback, trigger, user_data, destroy);
callback, trigger, user_data, destroy,
path, true);
}

unsigned int agent_request_pkey_passphrase(const char *path,
Expand All @@ -401,7 +478,8 @@ unsigned int agent_request_pkey_passphrase(const char *path,

return agent_queue_request(agent, AGENT_REQUEST_TYPE_PASSPHRASE,
message, agent_timeout_input_request(),
callback, trigger, user_data, destroy);
callback, trigger, user_data, destroy,
NULL, false);
}

unsigned int agent_request_user_name_password(const char *path,
Expand All @@ -427,7 +505,8 @@ unsigned int agent_request_user_name_password(const char *path,

return agent_queue_request(agent, AGENT_REQUEST_TYPE_USER_NAME_PASSWD,
message, agent_timeout_input_request(),
callback, trigger, user_data, destroy);
callback, trigger, user_data, destroy,
NULL, false);
}

unsigned int agent_request_user_password(const char *path, const char *user,
Expand All @@ -452,7 +531,8 @@ unsigned int agent_request_user_password(const char *path, const char *user,

return agent_queue_request(agent, AGENT_REQUEST_TYPE_PASSPHRASE,
message, agent_timeout_input_request(),
callback, trigger, user_data, destroy);
callback, trigger, user_data, destroy,
NULL, false);
}

static bool find_request(const void *a, const void *b)
Expand Down
1 change: 1 addition & 0 deletions src/agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ enum agent_result {

typedef void (*agent_request_passphrase_func_t) (enum agent_result result,
const char *passphrase,
bool store,
struct l_dbus_message *message,
void *user_data);
typedef void (*agent_request_user_name_passwd_func_t) (enum agent_result result,
Expand Down
12 changes: 12 additions & 0 deletions src/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct network {
char **nai_realms;
uint8_t *rc_ie;
bool sync_settings:1; /* should settings be synced on connect? */
bool agent_passphrase_transient:1;
bool ask_passphrase:1; /* Whether we should force-ask agent */
bool is_hs20:1;
bool anqp_pending:1; /* Set if there is a pending ANQP request */
Expand Down Expand Up @@ -324,6 +325,7 @@ static bool __network_set_passphrase(struct network *network,

network_reset_passphrase(network);
network->passphrase = l_strdup(passphrase);
network->agent_passphrase_transient = false;

network->sae_pt_19 = network_generate_sae_pt(network, 19);
network->sae_pt_20 = network_generate_sae_pt(network, 20);
Expand Down Expand Up @@ -664,6 +666,7 @@ static int network_load_psk(struct network *network, struct scan_bss *bss)

network_reset_passphrase(network);
network_reset_psk(network);
network->agent_passphrase_transient = false;
network->passphrase = l_steal_ptr(passphrase);
network->password_identifier = l_steal_ptr(password_id);

Expand Down Expand Up @@ -727,6 +730,9 @@ static void network_settings_save(struct network *network,
/* We only update the [Security] bits here, wipe the group first */
l_settings_remove_group(settings, "Security");

if (network->agent_passphrase_transient)
return;

if (network->psk)
l_settings_set_bytes(settings, "Security", "PreSharedKey",
network->psk, 32);
Expand Down Expand Up @@ -1316,6 +1322,7 @@ struct scan_bss *network_bss_select(struct network *network,

static void passphrase_callback(enum agent_result result,
const char *passphrase,
bool store,
struct l_dbus_message *message,
void *user_data)
{
Expand Down Expand Up @@ -1355,6 +1362,8 @@ static void passphrase_callback(enum agent_result result,
goto err;
}

network->agent_passphrase_transient = !store;

station_connect_network(station, network, bss, message);
l_dbus_message_unref(message);
return;
Expand Down Expand Up @@ -1424,11 +1433,14 @@ static bool eap_secret_info_match_local(const void *a, const void *b)
}

static void eap_password_callback(enum agent_result result, const char *value,
bool store,
struct l_dbus_message *message,
void *user_data)
{
struct eap_secret_request *req = user_data;

(void) store;

req->network->agent_request = 0;

if (value) {
Expand Down
Loading