eap: Validate settings, report passwords needed

With the goal of requesting the required passwords/passphrases, such as
the TLS private key passphrase, from the agent, add a static method
eap_check_settings to validate the settings and calculate what passwords
are needed for those settings, if any.  This is separate from
eap_load_settings because that can only be called later, once we've
got an eap state machine object.  We need to get all the needed EAP
credentials from the user before we even start connecting.

While we do this, we also validate the settings and output any error
messages through l_error (this could be changed so the messages go
somewhere else in the future), so I removed the error messages from
eap_load_settings and that method now assumes that eap_check_settings
has been called before.

eap_check_settings calls the appropriate method's .check_settings method
if the settings are complete enough to contain the method name.  The
policy is that any data can be provided inside the l_settings object
(from the network provisioning/config file), but some of the more
sensitive fields, like private key passwords, can be optionally omitted
and then the UI will ask for them and iwd will be careful with
caching them.

Within struct eap_secret_info, "id" is mainly for the EAP method to
locate the info in the list.  "value" is the actual value returned
by agent.  "parameter" is an optional string to be passed to the agent.
For a private key passphrase it may be the path to the key file, for a
password it may be the username for which the password is requested.
This commit is contained in:
Andrew Zaborowski 2018-04-18 07:03:22 +02:00 committed by Denis Kenzior
parent 15a037f633
commit 246e76c7b0
2 changed files with 123 additions and 9 deletions

107
src/eap.c
View File

@ -347,6 +347,102 @@ void eap_rx_packet(struct eap_state *eap, const uint8_t *pkt, size_t len)
}
}
bool eap_secret_info_match(const void *a, const void *b)
{
const struct eap_secret_info *s = a;
return !strcmp(s->id, b);
}
void eap_append_secret(struct l_queue **out_missing, enum eap_secret_type type,
const char *id, const char *parameter)
{
struct eap_secret_info *info;
if (!*out_missing)
*out_missing = l_queue_new();
info = l_new(struct eap_secret_info, 1);
info->id = l_strdup(id);
info->type = type;
info->parameter = l_strdup(parameter);
l_queue_push_tail(*out_missing, info);
}
void eap_secret_info_free(void *data)
{
struct eap_secret_info *info = data;
if (!info)
return;
if (info->value) {
memset(info->value, 0, strlen(info->value));
l_free(info->value);
}
if (info->parameter) {
memset(info->parameter, 0, strlen(info->parameter));
l_free(info->parameter);
}
l_free(info->id);
l_free(info);
}
bool eap_check_settings(struct l_settings *settings, struct l_queue *secrets,
const char *prefix, bool set_key_material,
struct l_queue **out_missing)
{
char setting[64];
const char *method_name;
const struct l_queue_entry *entry;
struct eap_method *method;
snprintf(setting, sizeof(setting), "%sMethod", prefix);
method_name = l_settings_get_value(settings, "Security", setting);
if (!method_name) {
l_error("Property %s missing", setting);
return false;
}
for (entry = l_queue_get_entries(eap_methods); entry;
entry = entry->next) {
method = entry->data;
if (!strcasecmp(method_name, method->name))
break;
}
if (!entry) {
l_error("EAP method \"%s\" unsupported", method_name);
return false;
}
/* Check if selected method is suitable for 802.1x */
if (set_key_material && !method->exports_msk) {
l_error("EAP method \"%s\" doesn't export key material",
method_name);
return false;
}
snprintf(setting, sizeof(setting), "%sIdentity", prefix);
if (!l_settings_get_value(settings, "Security", setting)) {
l_error("Property %s is missing", setting);
return false;
}
if (!method->check_settings)
return true;
return method->check_settings(settings, secrets, prefix, out_missing);
}
bool eap_load_settings(struct eap_state *eap, struct l_settings *settings,
const char *prefix)
{
@ -376,12 +472,8 @@ bool eap_load_settings(struct eap_state *eap, struct l_settings *settings,
return false;
/* Check if selected method is suitable for 802.1x */
if (eap->set_key_material && !eap->method->exports_msk) {
l_error("EAP method \"%s\" doesn't export key material",
method_name);
if (eap->set_key_material && !eap->method->exports_msk)
goto err;
}
if (eap->method->load_settings)
if (!eap->method->load_settings(eap, settings, prefix))
@ -396,11 +488,8 @@ bool eap_load_settings(struct eap_state *eap, struct l_settings *settings,
eap->identity = l_strdup(eap->method->get_identity(eap));
}
if (!eap->identity) {
l_error("EAP Identity is missing");
if (!eap->identity)
goto err;
}
return true;

View File

@ -33,6 +33,19 @@ enum eap_result {
EAP_RESULT_TIMEOUT,
};
enum eap_secret_type {
EAP_SECRET_LOCAL_PKEY_PASSPHRASE,
EAP_SECRET_REMOTE_PASSWORD,
EAP_SECRET_REMOTE_USER_PASSWORD,
};
struct eap_secret_info {
char *id;
enum eap_secret_type type;
char *parameter;
char *value;
};
typedef void (*eap_tx_packet_func_t)(const uint8_t *eap_data, size_t len,
void *user_data);
typedef void (*eap_key_material_func_t)(const uint8_t *msk_data, size_t msk_len,
@ -47,6 +60,14 @@ struct eap_state *eap_new(eap_tx_packet_func_t tx_packet,
eap_complete_func_t complete, void *user_data);
void eap_free(struct eap_state *eap);
bool eap_secret_info_match(const void *a, const void *b);
void eap_append_secret(struct l_queue **out_missing, enum eap_secret_type type,
const char *id, const char *parameter);
void eap_secret_info_free(void *data);
bool eap_check_settings(struct l_settings *settings, struct l_queue *secrets,
const char *prefix, bool set_key_material,
struct l_queue **out_missing);
bool eap_load_settings(struct eap_state *eap, struct l_settings *settings,
const char *prefix);
@ -101,6 +122,10 @@ struct eap_method {
bool exports_msk;
const char *name;
bool (*check_settings)(struct l_settings *settings,
struct l_queue *secrets, const char *prefix,
struct l_queue **out_missing);
bool (*load_settings)(struct eap_state *eap,
struct l_settings *settings,
const char *prefix);